class HTTP::Server

Overview

An HTTP server.

A server is given a handler that receives an HTTP::Server::Context that holds the HTTP::Request to process and must in turn configure and write to an HTTP::Server::Response.

The HTTP::Server::Response object has status and headers properties that can be configured before writing the response body. Once response output is written, changing the status and headers properties has no effect.

The HTTP::Server::Response is also a write-only IO, so all IO methods are available in it.

The handler given to a server can simply be a block that receives an HTTP::Server::Context, or it can be an HTTP::Handler. An HTTP::Handler has an optional next handler, so handlers can be chained. For example, an initial handler may handle exceptions in a subsequent handler and return a 500 status code (see HTTP::ErrorHandler), the next handler might log the incoming request (see HTTP::LogHandler), and the final handler deals with routing and application logic.

Simple Setup

A handler is given with a block.

require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world!"
end

server.bind_tcp 8080
puts "Listening on http://127.0.0.1:8080"
server.listen

With non-localhost bind address

require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world!"
end

server.bind_tcp "0.0.0.0", 8080
puts "Listening on http://0.0.0.0:8080"
server.listen

Add handlers

A series of handlers are chained.

require "http/server"

server = HTTP::Server.new([
  HTTP::ErrorHandler.new,
  HTTP::LogHandler.new,
  HTTP::CompressHandler.new,
  HTTP::StaticFileHandler.new("."),
])

server.bind_tcp "127.0.0.1", 8080
server.listen

Add handlers and block

A series of handlers is chained, the last one being the given block.

require "http/server"

server = HTTP::Server.new([
  HTTP::ErrorHandler.new,
  HTTP::LogHandler.new,
]) do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world!"
end

server.bind_tcp "0.0.0.0", 8080
server.listen

Defined in:

http/server/context.cr
http/server/response.cr
http/server.cr

Constructors

Class Method Summary

Instance Method Summary

Instance methods inherited from class Reference

==(other : self)
==(other : JSON::Any)
==(other : YAML::Any)
==(other)
==
, dup dup, hash(hasher) hash, inspect(io : IO) : Nil inspect, object_id : UInt64 object_id, pretty_print(pp) : Nil pretty_print, same?(other : Reference)
same?(other : Nil)
same?
, to_s(io : IO) : Nil to_s

Constructor methods inherited from class Reference

new new

Instance methods inherited from class Object

!=(other) !=, !~(other) !~, ==(other) ==, ===(other : JSON::Any)
===(other : YAML::Any)
===(other)
===
, =~(other) =~, class class, dup dup, hash(hasher)
hash
hash
, inspect(io : IO)
inspect
inspect
, itself itself, not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, tap(&block) tap, to_json(io : IO)
to_json
to_json
, to_pretty_json(indent : String = " ")
to_pretty_json(io : IO, indent : String = " ")
to_pretty_json
, to_s
to_s(io : IO)
to_s
, to_yaml(io : IO)
to_yaml
to_yaml
, try(&block) try, unsafe_as(type : T.class) forall T unsafe_as

Constructor methods inherited from class Object

from_json(string_or_io, root : String) : self
from_json(string_or_io) : self
from_json
, from_yaml(string_or_io : String | IO) : self from_yaml

Constructor Detail

def self.new(handlers : Array(HTTP::Handler), &handler : HTTP::Handler::HandlerProc) : self #

Creates a new HTTP server with a handler chain constructed from the handlers array and the given block.


[View source]
def self.new(&handler : HTTP::Handler::HandlerProc) : self #

Creates a new HTTP server with the given block as handler.


[View source]
def self.new(handlers : Array(HTTP::Handler)) : self #

Creates a new HTTP server with the handlers array as handler chain.


[View source]
def self.new(handler : HTTP::Handler | HTTP::Handler::HandlerProc) #

Creates a new HTTP server with the given handler.


[View source]

Class Method Detail

def self.build_middleware(handlers, last_handler : Context -> ? = nil) #

Builds all handlers as the middleware for HTTP::Server.


[View source]

Instance Method Detail

def addresses : Array(Socket::Address) #

[View source]
def bind(socket : Socket::Server) : Nil #

Adds a Socket::Server socket to this server.


[View source]
def bind(uri : String) : Socket::Address #

Parses a socket configuration from uri and adds it to this server. Returns the effective address it is bound to.

server = HTTP::Server.new { }
server.bind("tcp://localhost:80")  # => Socket::IPAddress.new("127.0.0.1", 8080)
server.bind("unix:///tmp/server.sock")  # => Socket::UNIXAddress.new("/tmp/server.sock")
server.bind("tls://127.0.0.1:443?key=private.key&cert=certificate.cert&ca=ca.crt)  # => Socket::IPAddress.new("127.0.0.1", 443)

[View source]
def bind(uri : URI) : Socket::Address #

Parses a socket configuration from uri and adds it to this server. Returns the effective address it is bound to.

server = HTTP::Server.new { }
server.bind("tcp://localhost:80")  # => Socket::IPAddress.new("127.0.0.1", 8080)
server.bind("unix:///tmp/server.sock")  # => Socket::UNIXAddress.new("/tmp/server.sock")
server.bind("tls://127.0.0.1:443?key=private.key&cert=certificate.cert&ca=ca.crt)  # => Socket::IPAddress.new("127.0.0.1", 443)

[View source]
def bind_tcp(host : String, port : Int32, reuse_port : Bool = false) : Socket::IPAddress #

Creates a TCPServer listenting on host:port and adds it as a socket, returning the local address and port the server listens on.

server = HTTP::Server.new { }
server.bind_tcp("127.0.0.100", 8080) # => Socket::IPAddress.new("127.0.0.100", 8080)

If reuse_port is true, it enables the SO_REUSEPORT socket option, which allows multiple processes to bind to the same port.


[View source]
def bind_tcp(port : Int32, reuse_port : Bool = false) : Socket::IPAddress #

Creates a TCPServer listenting on 127.0.0.1:port and adds it as a socket, returning the local address and port the server listens on.

server = HTTP::Server.new { }
server.bind_tcp(8080) # => Socket::IPAddress.new("127.0.0.1", 8080)

If reuse_port is true, it enables the SO_REUSEPORT socket option, which allows multiple processes to bind to the same port.


[View source]
def bind_tcp(address : Socket::IPAddress, reuse_port : Bool = false) : Socket::IPAddress #

Creates a TCPServer listenting on address and adds it as a socket, returning the local address and port the server listens on.

server = HTTP::Server.new { }
server.bind_tcp(Socket::IPAddress.new("127.0.0.100", 8080)) # => Socket::IPAddress.new("127.0.0.100", 8080)
server.bind_tcp(Socket::IPAddress.new("127.0.0.100", 0))    # => Socket::IPAddress.new("127.0.0.100", 35487)

If reuse_port is true, it enables the SO_REUSEPORT socket option, which allows multiple processes to bind to the same port.


[View source]

Creates an OpenSSL::SSL::Server and adds it as a socket.

The SSL server wraps a TCPServer listenting on an unused port on host.

server = HTTP::Server.new { }
context = OpenSSL::SSL::Context::Server.new
context.certificate_chain = "openssl.crt"
context.private_key = "openssl.key"
address = server.bind_tls Socket::IPAddress.new("127.0.0.1", 8000), context

[View source]
def bind_tls(host : String, port : Int32, context : OpenSSL::SSL::Context::Server, reuse_port : Bool = false) : Socket::IPAddress #

Creates an OpenSSL::SSL::Server and adds it as a socket.

The SSL server wraps a TCPServer listenting on host:port.

server = HTTP::Server.new { }
context = OpenSSL::SSL::Context::Server.new
context.certificate_chain = "openssl.crt"
context.private_key = "openssl.key"
server.bind_tls "127.0.0.1", 8080, context

[View source]
def bind_tls(host : String, context : OpenSSL::SSL::Context::Server) : Socket::IPAddress #

Creates an OpenSSL::SSL::Server and adds it as a socket.

The SSL server wraps a TCPServer listenting on an unused port on host.

server = HTTP::Server.new { }
context = OpenSSL::SSL::Context::Server.new
context.certificate_chain = "openssl.crt"
context.private_key = "openssl.key"
address = server.bind_tls "127.0.0.1", context

[View source]
def bind_unix(path : String) : Socket::UNIXAddress #

Creates a UNIXServer bound to path and adds it as a socket.

server = HTTP::Server.new { }
server.bind_unix "/tmp/my-socket.sock"

[View source]
def bind_unix(address : Socket::UNIXAddress) : Socket::UNIXAddress #

Creates a UNIXServer bound to address and adds it as a socket.

server = HTTP::Server.new { }
server.bind_unix(Socket::UNIXAddress.new("/tmp/my-socket.sock"))

[View source]
def bind_unused_port(host : String = "127.0.0.1", reuse_port : Bool = false) : Socket::IPAddress #

Creates a TCPServer listening on an unused port and adds it as a socket.

Returns the Socket::IPAddress with the determined port number.

server = HTTP::Server.new { }
server.bind_unused_port # => Socket::IPAddress.new("127.0.0.1", 12345)

[View source]
def close #

Gracefully terminates the server. It will process currently accepted requests, but it won't accept new connections.


[View source]
def closed? : Bool #

Returns true if this server is closed.


[View source]
def each_address(&block : Socket::Address -> ) #

Enumerates all addresses this server is bound to.


[View source]
def listen(port : Int32, reuse_port : Bool = false) #

Creates a TCPServer listenting on 127.0.0.1:port, adds it as a socket and starts the server. Blocks until the server is closed.

See #bind(port : Int32) for details.


[View source]
def listen(host : String, port : Int32, reuse_port : Bool = false) #

Creates a TCPServer listenting on host:port, adds it as a socket and starts the server. Blocks until the server is closed.

See #bind(host : String, port : Int32) for details.


[View source]
def listen #

Starts the server. Blocks until the server is closed.


[View source]
def listening? : Bool #

Returns true if this server is listening on it's sockets.


[View source]