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

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

Verify application can be run by compatable server?

Link to this section Types

Link to this type body()
body() :: boolean() | binary()

The body of a Raxx message.

The body can be:

  • part of the message (binary).
  • empty (false).
  • present but unknown (true).
Link to this type header()
header() :: {String.t(), String.t()}

Attribute value pair that can be serialized to an HTTP request or response

Link to this type headers()
headers() :: [header()]

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.

Link to this section Functions

Link to this function complete?(map)
complete?(message()) :: boolean()

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"
Link to this function delete_header(message, header)
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.

Link to this function fetch_query(request)
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"}}
Link to this function get_header(map, name, fallback \\ nil)
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", "/")
"/"
Link to this function html_escape(data)
html_escape(String.t()) :: String.t()

Escapes the given HTML to string.

iex> html_escape("foo")
"foo"

iex> html_escape("<foo>")
"&lt;foo&gt;"

iex> html_escape("quotes: \" & \'")
"quotes: &quot; &amp; &#39;"
Link to this function html_escape_to_iodata(data)
html_escape_to_iodata(String.t()) :: iodata()

Escapes the given HTML to iodata.

iex> html_escape_to_iodata("foo")
"foo"

iex> html_escape_to_iodata("<foo>")
[[[] | "&lt;"], "foo" | "&gt;"]

iex> html_escape_to_iodata("quotes: \" & \'")
[[[[], "quotes: " | "&quot;"], " " | "&amp;"], " " | "&#39;"]
Link to this function is_application?(arg)
is_application?({module(), any()}) :: boolean()

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
Link to this function normalized_path(request)
Link to this function reason_phrase(int)
reason_phrase(integer()) :: String.t()

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"
Link to this function redirect(url, opts \\ [])

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

Link to this function request(method, raw_url)

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
Link to this function response(status_code)

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
Link to this function set_body(message, body)
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"
Link to this function set_header(message, name, value)

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"}]
Link to this function set_query(request, query)
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"
Link to this function set_secure_browser_headers(response)

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"
Link to this function split_path(path_string)
split_path(String.t()) :: [String.t()]

Split a path on forward slashes.

Examples

iex> split_path("/foo/bar")
["foo", "bar"]
Link to this function tail(headers \\ [])
tail([{String.t(), String.t()}]) :: Raxx.Tail.t()

Construct a Raxx.Tail

Examples

iex> tail([{"digest", "opaque-data"}]).headers
[{"digest", "opaque-data"}]

iex> tail().headers
[]
Link to this function verify_application(arg)
verify_application({module(), any()}) ::
  {:ok, {module(), any()}} | {:error, String.t()}

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."}