class Kemal::Config

Overview

Stores all the configuration options for a Kemal application. It's a singleton and you can access it like.

Kemal.config

Defined in:

kemal/config.cr

Constant Summary

CUSTOM_HANDLERS = [] of Tuple(Int32 | ::Nil, HTTP::Handler)
ERROR_HANDLERS = {} of Int32 => (HTTP::Server::Context, Exception -> String)
EXCEPTION_HANDLERS = {} of Exception.class => (HTTP::Server::Context, Exception -> String)
FILTER_HANDLERS = [] of HTTP::Handler
HANDLERS = [] of HTTP::Handler
INSTANCE = Config.new

Constructors

Instance Method Summary

Constructor Detail

def self.new #

[View source]

Instance Method Detail

def add_error_handler(status_code : Int32, &handler : HTTP::Server::Context, Exception -> _) #

Adds an error handler for the given HTTP status code


[View source]
def add_exception_handler(exception : Exception.class, &handler : HTTP::Server::Context, Exception -> _) #

Adds an error handler for the given exception


[View source]
def add_filter_handler(handler : HTTP::Handler) #

[View source]
def add_handler(handler : HTTP::Handler, position : Int32) #

[View source]
def add_handler(handler : HTTP::Handler) #

[View source]
def always_rescue : Bool #

[View source]
def always_rescue=(always_rescue : Bool) #

[View source]
def app_name : String #

[View source]
def app_name=(app_name : String) #

[View source]
def clear #

Returns every setting to its default and empties the handler tables. Specs call this after each example; a setting #clear forgets is one that leaks from the example that set it into the next.


[View source]
def env : String #

[View source]
def env=(env : String) #

[View source]
def error_handlers #

Returns the defined error handlers for HTTP status codes


[View source]
def exception_handlers #

Returns the defined error handlers for exceptions


[View source]
def extra_options : OptionParser -> Nil? #

[View source]
def extra_options(&extra_options : OptionParser -> ) #

[View source]
def extra_options=(extra_options : Nil | OptionParser -> _) #

[View source]
def handlers #

[View source]
def handlers=(handlers : Array(HTTP::Handler)) #

[View source]
def host_binding : String #

[View source]
def host_binding=(host_binding : String) #

[View source]
def logger #

DEPRECATED Use standard library Log


[View source]
def logger=(logger : Kemal::BaseLogHandler) #

DEPRECATED Use standard library Log


[View source]
def logging : Bool #

[View source]
def logging=(logging : Bool) #

[View source]
def max_file_uploads : Int32 #

Maximum number of file parts accepted in a single multipart/form-data request.

Every file part is spooled to its own temporary file, which stays open until the request is over, so the count is what bounds the file descriptors and disk entries one request can hold — #max_request_body_size does not: an 8 MB body fits some 100,000 one-byte parts. A request carrying more file parts than this is answered with 413 before the next one is written to disk; the ones already spooled are cleaned up with the request. Form fields without a filename do not count. 0 refuses file uploads altogether.


[View source]
def max_file_uploads=(max_file_uploads : Int32) #

Maximum number of file parts accepted in a single multipart/form-data request.

Every file part is spooled to its own temporary file, which stays open until the request is over, so the count is what bounds the file descriptors and disk entries one request can hold — #max_request_body_size does not: an 8 MB body fits some 100,000 one-byte parts. A request carrying more file parts than this is answered with 413 before the next one is written to disk; the ones already spooled are cleaned up with the request. Form fields without a filename do not count. 0 refuses file uploads altogether.


[View source]
def max_multipart_form_field_size : Int32 #

[View source]
def max_multipart_form_field_size=(max_multipart_form_field_size : Int32) #

[View source]
def max_ranges : Int32 #

Maximum number of byte ranges accepted in a single Range request header.

A Range header listing more parts than this is ignored and the full representation is served with 200 instead. Since send_file also refuses range sets asking for more bytes in total than the file holds, a multi-range response stays within the file's own size plus roughly 150 bytes of multipart framing per part. Raising this therefore raises the framing a single request can ask for; 0 ignores Range headers entirely and advertises Accept-Ranges: none.

Without a bound, a header such as bytes=0-,0-,0-,... makes the server re-read the whole file once per range. RFC 9110 §14.2 explicitly allows rejecting such range sets, as they indicate "either a broken client or a deliberate denial-of-service attack".


[View source]
def max_ranges=(max_ranges : Int32) #

Maximum number of byte ranges accepted in a single Range request header.

A Range header listing more parts than this is ignored and the full representation is served with 200 instead. Since send_file also refuses range sets asking for more bytes in total than the file holds, a multi-range response stays within the file's own size plus roughly 150 bytes of multipart framing per part. Raising this therefore raises the framing a single request can ask for; 0 ignores Range headers entirely and advertises Accept-Ranges: none.

Without a bound, a header such as bytes=0-,0-,0-,... makes the server re-read the whole file once per range. RFC 9110 §14.2 explicitly allows rejecting such range sets, as they indicate "either a broken client or a deliberate denial-of-service attack".


[View source]
def max_request_body_size : Int32 #

[View source]
def max_request_body_size=(max_request_body_size : Int32) #

[View source]
def max_route_cache_size : Int32 #

[View source]
def max_route_cache_size=(max_route_cache_size : Int32) #

[View source]
def port : Int32 #

[View source]
def port=(port : Int32) #

[View source]
def powered_by_header=(powered_by_header : Bool) #

[View source]
def powered_by_header? : Bool #

[View source]
def public_folder : String #

[View source]
def public_folder=(public_folder : String) #

[View source]
def running : Bool #

[View source]
def running=(running : Bool) #

[View source]
def scheme #

[View source]
def serve_static : Bool | Hash(String, Bool) #

[View source]
def serve_static=(serve_static : Bool | Hash(String, Bool)) #

[View source]
def server : HTTP::Server | Nil #

[View source]
def server=(server : HTTP::Server | Nil) #

[View source]
def setup #

[View source]
def show_exceptions=(show_exceptions : Bool | Nil) #

Whether an unhandled exception is answered with the development error page — exception message, backtrace with source, response headers, cookies — or the static production page that says nothing about the failure.

Unset (nil, the default) means "only in the development environment". Every other environment name, including one that is misspelt or unknown, gets the production page: the development page exists to debug locally, not to serve as the fallback for a KEMAL_ENV that failed to say production. Set it to true to show the page in another environment, or to false to never show it.


[View source]
def show_exceptions? : Bool #

[View source]
def shutdown_message : Bool #

[View source]
def shutdown_message=(shutdown_message : Bool) #

[View source]
def shutdown_timeout : Time::Span #

How long Kemal.run waits, once the server has been stopped, for the requests that were being served at that moment to finish. Nothing in flight: it returns at once. Still something in flight when the time is up: it logs a warning and returns anyway, so a stuck handler cannot hold a deploy hostage.

A WebSocket or SSE connection counts as in flight for as long as it stays open, so an application holding such connections waits the full time on every shutdown unless it closes them itself from the Kemal.run block or a Kemal.stop caller. A second termination signal during the wait exits immediately.


[View source]
def shutdown_timeout=(shutdown_timeout : Time::Span) #

How long Kemal.run waits, once the server has been stopped, for the requests that were being served at that moment to finish. Nothing in flight: it returns at once. Still something in flight when the time is up: it logs a warning and returns anyway, so a stuck handler cannot hold a deploy hostage.

A WebSocket or SSE connection counts as in flight for as long as it stays open, so an application holding such connections waits the full time on every shutdown unless it closes them itself from the Kemal.run block or a Kemal.stop caller. A second termination signal during the wait exits immediately.


[View source]
def ssl : OpenSSL::SSL::Context::Server? #

[View source]
def ssl=(ssl : Nil | OpenSSL::SSL::Context::Server) #

[View source]
def static_headers : HTTP::Server::Context, String, File::Info -> | Nil #

[View source]
def static_headers=(static_headers : HTTP::Server::Context, String, File::Info -> | Nil) #

[View source]
def websocket_allowed_origins : Array(String) #

WebSocket Origin policy for upgrade requests.

  • Empty (default): same-origin — Origin must match the request Host (scheme is taken from Origin, so TLS termination in front of Kemal still works). Missing or empty Origin is rejected with 403.
  • Non-empty allowlist: Origin must match one of the entries after normalization (scheme/host/port only). Missing Origin is rejected.
  • Include "*" to allow any origin, including requests without Origin (previous allow-all behavior).
  • Use "null" to allow the browser's opaque "null" origin.

Entries use the serialized origin form, e.g. "https://example.com" or "http://localhost:3000".


[View source]
def websocket_allowed_origins=(websocket_allowed_origins : Array(String)) #

WebSocket Origin policy for upgrade requests.

  • Empty (default): same-origin — Origin must match the request Host (scheme is taken from Origin, so TLS termination in front of Kemal still works). Missing or empty Origin is rejected with 403.
  • Non-empty allowlist: Origin must match one of the entries after normalization (scheme/host/port only). Missing Origin is rejected.
  • Include "*" to allow any origin, including requests without Origin (previous allow-all behavior).
  • Use "null" to allow the browser's opaque "null" origin.

Entries use the serialized origin form, e.g. "https://example.com" or "http://localhost:3000".


[View source]