raxx v0.15.2 Raxx
Tooling to work with HTTP.
Several data structures are defined to model parts of the communication between client and server.
Raxx.Request
: metadata sent by a client before sending content.Raxx.Response
: metadata sent by a server before sending content.Raxx.Data
: A part of a messages content.Raxx.Tail
: metadata set by client or server to conclude communication.
This module contains functions to create and manipulate these structures.
See Raxx.Server
for implementing a web application.
Link to this section Summary
Types
The body of a Raxx message
Attribute value pair that can be serialized to an HTTP request or response
List of HTTP headers
Either a Raxx.Request.t
or a Raxx.Response.t
Set of all components that make up a message to or from server
Functions
Does the message struct contain all the data to be sent
Construct a Raxx.Data
Delete a header, if present from a request or response
Fetch the decoded query from a request
Get the value of a header field
Escapes the given HTML to string
Escapes the given HTML to iodata
Can application be run by compatable server?
The RFC7231 specified reason phrase for each known HTTP status code. Extra reason phrases can be defined in raxx config under extra_status
Create a response to redirect client to the given url
Construct a Raxx.Request
Construct a Raxx.Response
Add a complete body to a message
Set the value of a header field
Add a query value to a request
Put headers that improve browser security
Split a path on forward slashes
Construct a Raxx.Tail
Verify application can be run by compatable server?
Link to this section Types
The body of a Raxx message.
The body can be:
- part of the message (
binary
). - empty (
false
). - present but unknown (
true
).
Attribute value pair that can be serialized to an HTTP request or response
List of HTTP headers.
Either a Raxx.Request.t
or a Raxx.Response.t
part() :: Raxx.Request.t() | Raxx.Response.t() | Raxx.Data.t() | Raxx.Tail.t()
Set of all components that make up a message to or from server.
Link to this section Functions
Does the message struct contain all the data to be sent.
Examples
iex> request(:GET, "/")
...> |> complete?()
true
iex> response(:ok)
...> |> set_body("Hello, World!")
...> |> complete?()
true
iex> response(:ok)
...> |> set_body(true)
...> |> complete?()
false
Construct a Raxx.Data
Wrap a piece of data as being part of a message’s body.
Examples
iex> data("Hi").data
"Hi"
delete_header(Raxx.Request.t(), String.t()) :: Raxx.Request.t()
delete_header(Raxx.Response.t(), String.t()) :: Raxx.Response.t()
Delete a header, if present from a request or response.
fetch_query(Raxx.Request.t()) :: {:ok, %{optional(binary()) => binary()}}
Fetch the decoded query from a request
A map is always returned, even in the case of a request without a query string.
Examples
iex> request(:GET, "/")
...> |> fetch_query()
{:ok, %{}}
iex> request(:GET, "/?")
...> |> fetch_query()
{:ok, %{}}
iex> request(:GET, "/?foo=bar")
...> |> fetch_query()
{:ok, %{"foo" => "bar"}}
get_header(Raxx.Request.t(), String.t(), String.t() | nil) :: String.t() | nil
get_header(Raxx.Response.t(), String.t(), String.t() | nil) :: String.t() | nil
Get the value of a header field.
Examples
iex> response(:ok)
...> |> set_header("content-type", "text/html")
...> |> get_header("content-type")
"text/html"
iex> response(:ok)
...> |> set_header("content-type", "text/html")
...> |> get_header("location")
nil
iex> response(:ok)
...> |> set_header("content-type", "text/html")
...> |> get_header("content-type", "text/plain")
"text/html"
iex> response(:ok)
...> |> set_header("content-type", "text/html")
...> |> get_header("location", "/")
"/"
Escapes the given HTML to string.
iex> html_escape("foo")
"foo"
iex> html_escape("<foo>")
"<foo>"
iex> html_escape("quotes: \" & \'")
"quotes: " & '"
Escapes the given HTML to iodata.
iex> html_escape_to_iodata("foo")
"foo"
iex> html_escape_to_iodata("<foo>")
[[[] | "<"], "foo" | ">"]
iex> html_escape_to_iodata("quotes: \" & \'")
[[[[], "quotes: " | """], " " | "&"], " " | "'"]
Can application be run by compatable server?
Examples
iex> is_application?({Raxx.ServerTest.DefaultServer, %{}})
true
iex> is_application?({GenServer, %{}})
false
iex> is_application?({NotAModule, %{}})
false
The RFC7231 specified reason phrase for each known HTTP status code. Extra reason phrases can be defined in raxx config under extra_status.
For example.
config :raxx,
:extra_statuses, ["422", "Unprocessable Entity"]
Examples
iex> reason_phrase(200)
"OK"
iex> reason_phrase(500)
"Internal Server Error"
iex> reason_phrase(422)
"Unprocessable Entity"
Create a response to redirect client to the given url.
Response status can be set using the :status
option.
Examples
iex> redirect(“/foo”) …> |> get_header(“location”) “/foo”
iex> redirect(“/foo”) …> |> get_header(“content-type”) “text/html”
iex> redirect(“/foo”) …> |> Map.get(:body) ~s(
This resource has moved here.)iex> redirect(“/foo”) …> |> Map.get(:status) 303
iex> redirect(“/foo”, status: 301) …> |> Map.get(:status) 301
iex> redirect(“/foo”, status: :moved_permanently) …> |> Map.get(:status) 301
Notes
This implementation was lifted from the sugar framework and is sufficient for many usecases.
I would like to implement a back
function.
Complication with such functionality are discussed here - https://github.com/phoenixframework/phoenix/pull/1402
Sinatra has a very complete test suite including a back implementation - https://github.com/sinatra/sinatra/blob/9bd0d40229f76ff60d81c01ad2f4b1a8e6f31e05/test/helpers_test.rb#L183
request(Raxx.Request.method(), String.t() | URI.t()) :: Raxx.Request.t()
Construct a Raxx.Request
.
An HTTP request must have a method and path.
If the location argument is a relative path the scheme and authority values will be unset. When these values can be inferred from the location they will be set.
The method must be an atom for one of the HTTP methods
[:GET, :POST, :PUT, :PATCH, :DELETE, :HEAD, :OPTIONS]
The request will have no body or headers.
These can be added with set_header/3
and set_body/2
.
Examples
iex> request(:HEAD, "/").method
:HEAD
iex> request(:GET, "/").path
[]
iex> request(:GET, "/foo/bar").path
["foo", "bar"]
iex> request(:GET, "https:///").scheme
:https
iex> request(:GET, "https://example.com").authority
"example.com"
iex> request(:GET, "/").query
nil
iex> request(:GET, "/?").query
""
iex> request(:GET, "/?foo=bar").query
"foo=bar"
iex> request(:GET, "/").headers
[]
iex> request(:GET, "/").body
false
response(Raxx.Response.status_code() | atom()) :: Raxx.Response.t()
Construct a Raxx.Response
.
The responses HTTP status code can be provided as an integer, or will be translated from a known atom.
The response will have no body or headers.
These can be added with set_header/3
and set_body/2
.
Examples
iex> response(200).status
200
iex> response(:no_content).status
204
iex> response(200).headers
[]
iex> response(200).body
false
set_body(Raxx.Request.t(), body()) :: Raxx.Request.t()
set_body(Raxx.Response.t(), body()) :: Raxx.Response.t()
Add a complete body to a message.
Examples
iex> request(:GET, "/")
...> |> set_body("Hello")
...> |> Map.get(:body)
"Hello"
set_header(Raxx.Request.t(), String.t(), String.t()) :: Raxx.Request.t()
set_header(Raxx.Response.t(), String.t(), String.t()) :: Raxx.Response.t()
Set the value of a header field.
Examples
iex> request(:GET, "/")
...> |> set_header("referer", "example.com")
...> |> set_header("accept", "text/html")
...> |> Map.get(:headers)
[{"referer", "example.com"}, {"accept", "text/html"}]
set_query(Raxx.Request.t(), %{optional(binary()) => binary()}) :: Raxx.Request.t()
Add a query value to a request
Examples
iex> request(:GET, "/")
...> |> set_query(%{"foo" => "bar"})
...> |> Map.get(:query)
"foo=bar"
Put headers that improve browser security.
The following headers are set:
- x-frame-options - set to SAMEORIGIN to avoid clickjacking through iframes unless in the same origin
- x-content-type-options - set to nosniff. This requires script and style tags to be sent with proper content type
- x-xss-protection - set to “1; mode=block” to improve XSS protection on both Chrome and IE
- x-download-options - set to noopen to instruct the browser not to open a download directly in the browser, to avoid HTML files rendering inline and accessing the security context of the application (like critical domain cookies)
- x-permitted-cross-domain-policies - set to none to restrict Adobe Flash Player’s access to data
Examples
iex> response(:ok)
...> |> set_secure_browser_headers()
...> |> get_header("x-frame-options")
"SAMEORIGIN"
iex> response(:ok)
...> |> set_secure_browser_headers()
...> |> get_header("x-xss-protection")
"1; mode=block"
iex> response(:ok)
...> |> set_secure_browser_headers()
...> |> get_header("x-content-type-options")
"nosniff"
iex> response(:ok)
...> |> set_secure_browser_headers()
...> |> get_header("x-download-options")
"noopen"
iex> response(:ok)
...> |> set_secure_browser_headers()
...> |> get_header("x-permitted-cross-domain-policies")
"none"
Construct a Raxx.Tail
Examples
iex> tail([{"digest", "opaque-data"}]).headers
[{"digest", "opaque-data"}]
iex> tail().headers
[]
Verify application can be run by compatable server?
Examples
iex> verify_application({Raxx.ServerTest.DefaultServer, %{}})
{:ok, {Raxx.ServerTest.DefaultServer, %{}}}
iex> verify_application({GenServer, %{}})
{:error, "module [`GenServer`](https://hexdocs.pm/elixir/GenServer.html) does not implement [`Raxx.Server`](Raxx.Server.html) behaviour."}
iex> verify_application({NotAModule, %{}})
{:error, "module `NotAModule` is not available."}