Packages
raxx
0.17.5
1.1.0
1.0.1
1.0.0
1.0.0-rc.3
1.0.0-rc.2
retired
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.18.1
0.18.0
0.17.6
0.17.5
0.17.4
0.17.3
0.17.2
0.17.1
0.17.0
0.16.1
0.16.0
retired
0.15.11
0.15.10
0.15.9
0.15.8
0.15.7
0.15.6
0.15.5
0.15.4
0.15.3
0.15.2
0.15.1
0.15.0
0.14.14
0.14.13
0.14.12
0.14.11
0.14.10
0.14.9
0.14.8
0.14.7
0.14.6
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.0
0.12.3
0.12.2
0.12.1
0.12.0
0.11.1
0.11.0
0.10.5
0.10.4
0.10.3
0.10.2
0.10.1
0.10.0
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.4.3
0.4.2
0.4.1
0.4.0
0.3.0
0.2.0
0.1.0
0.0.1
Interface for HTTP webservers, frameworks and clients.
Current section
Files
Jump to
Current section
Files
lib/raxx/simple_server.ex
defmodule Raxx.SimpleServer do
@moduledoc """
Server interface for simple `request -> response` interactions.
*Modules that use Raxx.SimpleServer implement the Raxx.Server behaviour.
Default implementations are provided for the streaming interface to buffer the request before a single call to `handle_request/2`.*
## Example
Echo the body of a request to the client
defmodule EchoServer do
use Raxx.SimpleServer, maximum_body_length: 12 * 1024 * 1024
def handle_request(%Raxx.Request{method: :POST, path: [], body: body}, _state) do
response(:ok)
|> set_header("content-type", "text/plain")
|> set_body(body)
end
end
## Options
- **maximum_body_length** (default 8MB) the maximum sized body that will be automatically buffered.
For large requests, e.g. file uploads, consider implementing a streaming server.
"""
@typedoc """
State of application server.
Original value is the configuration given when starting the raxx application.
"""
@type state :: any()
@doc """
Called with a complete request once all the data parts of a body are received.
Passed a `Raxx.Request` and server configuration.
Note the value of the request body will be a string.
"""
@callback handle_request(Raxx.Request.t(), state()) :: Raxx.Response.t()
use Raxx.View, template: "simple_server.html.eex", arguments: [:module]
@eight_MB 8 * 1024 * 1024
defmacro __using__(options) do
{options, []} = Module.eval_quoted(__CALLER__, options)
maximum_body_length = Keyword.get(options, :maximum_body_length, @eight_MB)
quote do
@behaviour unquote(__MODULE__)
import Raxx
@behaviour Raxx.Server
@impl Raxx.Server
def handle_head(request = %{body: false}, state) do
response = __MODULE__.handle_request(%{request | body: ""}, state)
case response do
%{body: true} -> raise "Incomplete response"
_ -> response
end
end
def handle_head(request = %{body: true}, state) do
{[], {request, [], state}}
end
@impl Raxx.Server
def handle_data(data, {request, iodata_buffer, state}) do
iodata_buffer = [data | iodata_buffer]
if :erlang.iolist_size(iodata_buffer) <= unquote(maximum_body_length) do
{[], {request, iodata_buffer, state}}
else
Raxx.error_response(:payload_too_large)
end
end
@impl Raxx.Server
def handle_tail([], {request, iodata_buffer, state}) do
body = :erlang.iolist_to_binary(Enum.reverse(iodata_buffer))
response = __MODULE__.handle_request(%{request | body: body}, state)
case response do
%{body: true} -> raise "Incomplete response"
_ -> response
end
end
@impl Raxx.Server
def handle_info(message, state) do
require Logger
Logger.warn(
"#{inspect(self())} received unexpected message in handle_info/2: #{inspect(message)}"
)
{[], state}
end
@impl Raxx.SimpleServer
def handle_request(_, _) do
response(:not_found)
|> Raxx.SimpleServer.render(__MODULE__)
end
defoverridable unquote(__MODULE__)
end
end
end