0.0
No release in over 3 years
Low commit activity in last 3 years
Simple server for the Gemini protocol
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 1.1

Runtime

 Project Readme

GeminiServer

A simple server for the Gemini protocol, with an API inspired by Sinatra.

Usage

Use the built-in executable to serve the current directory.

$ gem install gemini_server
Successfully installed gemini_server-0.1.0
1 gem installed
$ gemini_server -h
Usage: gemini_server [options]
    -p, --port PORT                  Port to listen on
        --cert-path PATH             Path to cert file
        --key-path PATH              Path to key file
        --charset CHARSET            Charset of text/* files
        --lang LANG                  Language of text/* files

Or require the library to declare custom routes in Ruby.

require "gemini_server"

server = GeminiServer.new

server.route("/greeting/:friend") do
  if params["friend"] == "Gary"
    gone "Gary and I aren't on speaking terms, sorry."
  else
    success "Hi there, #{params["friend"]}!"
  end
end

server.route("/farewell") do
  lang "pig-latin"
  success "arewellfay!"
end

server.listen("0.0.0.0", 1965)

Initialization options

cert*
A SSL certificate. Either a OpenSSL::X509::Certificate object, or a string.
cert_path*
Path to a SSL certificate file. Defaults to the value of the env variable GEMINI_CERT_PATH. Ignored if cert option is supplied.
key*
A SSL key. Either a OpenSSL::PKey object, or a string.
key_path*
Path to a private key file. Defaults to the value of the env variable GEMINI_KEY_PATH. Ignored if key option is supplied.
mime_type
Sets the default MIME type for successful responses. Defaults to text/gemini, or inferred by the name of the file being served.
charset
If set, includes the charset in the response's MIME type.
lang
If set, includes the language in the response's MIME type, if the MIME type is text/gemini. Per the Gemini spec, "Valid values for the "lang" parameter are comma-separated lists of one or more language tags as defined in RFC4646."
public_folder
Path to a location from which the server will serve static files. If not set, the server will not serve any static files.
views_folder
Path to the location of ERB templates. If not set, defaults to current directory.

* The option pairs cert and cert_path, and likewise key and key_path, are mutually exclusive, so they are technically optional. But per the Gemini spec, connections must use TLS, so it is a runtime error if neither option, nor either of the fallback env variables, are used.

Route handlers

To define a route handler, use GeminiServer#route:

server = GeminiServer.new
server.route("/path/to/route/:variable") do
  # route logic
end

The route method takes a Mustermann matcher string and a block.

Within the block, code has access to these methods:

params
Returns a hash of params parsed from the request path.
uri
Returns the full URI of the request.
mime_type(type)
Sets the MIME type of the response.
charset(ch)
Sets the charset of the response, overriding the server's default charset.
lang(l)
Sets the lang of the response, overriding the server's default lang.
erb(filename, locals: {})
Renders an ERB template located at filename, then sets status to success. MIME type is inferred by the template extension. The template will have access to any instance variables defined in the handler block, as well as any local variables passed in via the locals keyword param.
respond(code, meta, body=nil)
Sets the response code, meta, and optional body. It's probably easier to use erb method, or any of the convenience status methods in the next section.

ERB templates

Using an ERB template automatically sets the status to 20 (success) because a success is the only type of response that can contain a body. It also tries to infer the MIME type from the template extension (excluding any .erb).

ERB rendering can define local variables, like in Sinatra:

server.route("/hithere/:friend") do
  erb "hithere.gmi", locals: { friend: params["friend"] }
end
<!-- hithere.gmi.erb -->
# Hi there!

Hi there, <%= friend %>.

ERB templates have the params hash available as a local var:

server.route("/hithere/:friend") do
  erb "hithere.gmi"
end
<!-- hithere.gmi.erb -->
# Hi there!

Hi there, <%= params["friend"] %>.

Status methods

Each of these methods are available within a route handler block. Forgetting to use a status method defaults to a temporary failure. See Gemini Specification for an explanation of each response status.

  • input(prompt)
  • sensitive_input(prompt)
  • success(body, mime_type=nil)
  • redirect_temporary(url)
  • redirect_permanent(url)
  • temporary_failure(explanation = "Temporary failure")
  • server_unavailable(explanation = "Server unavailable")
  • cgi_error(explanation = "CGI error")
  • proxy_error(explanation = "Proxy error")
  • slow_down(delay)
  • permanent_failure(explanation = "Permanent failure")
  • not_found(explanation = "Not found")
  • gone(explanation = "Gone")
  • proxy_request_refused(explanation = "Proxy request refused")
  • bad_request(explanation = "Bad request")
  • client_certificate_required(explanation = "Client certificate required")
  • certificate_not_authorized(explanation = "Certificate not authorized")
  • certificate_not_valid(explanation = "Certificate not valid")

Static file serving

To serve static files, set the initialization option public_folder to the location of your static files. If no route handlers match a request, the server will look for a static file to serve in that location instead. If the public_folder option is unset, no static files will be served.