Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve HTTP::Server docs #7251

Merged
merged 4 commits into from
Jan 24, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 69 additions & 51 deletions src/http/server.cr
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,10 @@ require "./common"
require "openssl"
{% end %}

# An HTTP server.
# A concurrent HTTP server implementation.
#
# 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.
# A server is initialized with a handler chain responsible for processing each
# incoming request.
#
# ```
# require "http/server"
Expand All @@ -39,29 +21,30 @@ require "./common"
# context.response.print "Hello world!"
# end
#
# server.bind_tcp 8080
# puts "Listening on http://127.0.0.1:8080"
# address = server.bind_tcp 8080
# puts "Listening on http://#{address}"
# server.listen
# ```
#
# ### With non-localhost bind address
# ## Request processing
#
# ```
# require "http/server"
# The handler chain receives an instance of `HTTP::Server::Context` that holds
# the `HTTP::Request` to process and a `HTTP::Server::Response` which it can
# configure and write to.
#
# server = HTTP::Server.new do |context|
# context.response.content_type = "text/plain"
# context.response.print "Hello world!"
# end
# Each connection is processed concurrently in a separate `Fiber` and can handle
# multiple subsequent requests-response cycles with connection keep-alive.
#
# server.bind_tcp "0.0.0.0", 8080
# puts "Listening on http://0.0.0.0:8080"
# server.listen
# ```
# ### Handler chain
#
# ### Add handlers
# The handler given to a server can simply be a block that receives an `HTTP::Server::Context`,
# or it can be an instance of `HTTP::Handler`. An `HTTP::Handler` has a `#next`
# method to forward processing to the next handler in the chain.
#
# A series of handlers are chained.
# For example, an initial handler might handle exceptions raised from subsequent
# handlers and return a `500 Server Error` status (see `HTTP::ErrorHandler`).
# The next handler might log all incoming requests (see `HTTP::LogHandler`).
# And the final handler deals with routing and application logic.
#
# ```
# require "http/server"
Expand All @@ -77,24 +60,59 @@ require "./common"
# server.listen
# ```
#
# ### Add handlers and block
# ### Response object
#
# A series of handlers is chained, the last one being the given block.
# The `HTTP::Server::Response` object has `status` and `headers` properties that can be
# configured before writing the response body. Once any response output has been
# written, changing the `status` and `headers` properties has no effect.
#
# The `HTTP::Server::Response` is a write-only `IO`, so all `IO` methods are available
# on it for sending the response body.
#
# ## Binding to sockets
#
# The server can be bound to one ore more server sockets (see `#bind`)
#
# Supported types:
#
# * TCP socket: `#bind_tcp`, `#bind_unused_port`
# * TCP socket with TLS/SSL: `#bind_tls`
# * Unix socket `#bind_unix`
#
# `#bind(uri : URI)` and `#bind(uri : String)` parse socket configuration for
# one of these types from an `URI`. This can be useful for injecting plain text
# configuration values.
#
# Each of these methods returns the `Socket::Address` that was added to this
# server.
#
# ```
# require "http/server"
#
# server = HTTP::Server.new([
# HTTP::ErrorHandler.new,
# HTTP::LogHandler.new,
# ]) do |context|
# 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
# address = server.bind_tcp "0.0.0.0", 8080
# puts "Listening on http://#{address}"
# server.listen
# ```
#
# It is also possible to bind a generic `Socket::Server` using
# `#bind(socket : Socket::Server)` which can be used for custom network protocol
# configurations.
#
# ## Server loop
#
# After defining all server sockets to listen to, the server can be started by
# calling `#listen`. This call blocks until the server is closed.
#
# A server can be closed by calling `#close`. This closes the server sockets and
# stops processing any new requests, even on connections with keep-alive enabled.
# Currently processing requests are not interrupted but also not waited for.
# In order to give them some grace period for finishing, the calling context
# can add a timeout like `sleep 10.seconds` after `#listen` returns.
class HTTP::Server
@sockets = [] of Socket::Server

Expand Down Expand Up @@ -125,7 +143,7 @@ class HTTP::Server
@processor = RequestProcessor.new(handler)
end

# Creates a `TCPServer` listenting on `host:port` and adds it as a socket, returning the local address
# Creates a `TCPServer` listening on `host:port` and adds it as a socket, returning the local address
# and port the server listens on.
#
# ```
Expand All @@ -143,7 +161,7 @@ class HTTP::Server
tcp_server.local_address
end

# Creates a `TCPServer` listenting on `127.0.0.1:port` and adds it as a socket,
# Creates a `TCPServer` listening on `127.0.0.1:port` and adds it as a socket,
# returning the local address and port the server listens on.
#
# ```
Expand All @@ -157,7 +175,7 @@ class HTTP::Server
bind_tcp Socket::IPAddress::LOOPBACK, port, reuse_port
end

# Creates a `TCPServer` listenting on *address* and adds it as a socket, returning the local address
# Creates a `TCPServer` listening on *address* and adds it as a socket, returning the local address
# and port the server listens on.
#
# ```
Expand Down Expand Up @@ -211,7 +229,7 @@ class HTTP::Server
{% unless flag?(:without_openssl) %}
# Creates an `OpenSSL::SSL::Server` and adds it as a socket.
#
# The SSL server wraps a `TCPServer` listenting on `host:port`.
# The SSL server wraps a `TCPServer` listening on `host:port`.
#
# ```
# server = HTTP::Server.new { }
Expand All @@ -231,7 +249,7 @@ class HTTP::Server

# Creates an `OpenSSL::SSL::Server` and adds it as a socket.
#
# The SSL server wraps a `TCPServer` listenting on an unused port on *host*.
# The SSL server wraps a `TCPServer` listening on an unused port on *host*.
#
# ```
# server = HTTP::Server.new { }
Expand All @@ -246,7 +264,7 @@ class HTTP::Server

# Creates an `OpenSSL::SSL::Server` and adds it as a socket.
#
# The SSL server wraps a `TCPServer` listenting on an unused port on *host*.
# The SSL server wraps a `TCPServer` listening on an unused port on *host*.
#
# ```
# server = HTTP::Server.new { }
Expand Down Expand Up @@ -317,7 +335,7 @@ class HTTP::Server
array
end

# Creates a `TCPServer` listenting on `127.0.0.1:port`, adds it as a socket
# Creates a `TCPServer` listening 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.
Expand All @@ -327,7 +345,7 @@ class HTTP::Server
listen
end

# Creates a `TCPServer` listenting on `host:port`, adds it as a socket
# Creates a `TCPServer` listening 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.
Expand Down