defmodule HTTPMessage do import String defstruct method: "GET", version: "HTTP/1.1", url: "/", fields: [], body: "" def parse(source) do # Parse message sections: {header, body} = case split(source, ["\r\n\r\n", "\n\n"], parts: 2) do [header, body] -> {header, body} [header] -> {header, ""} [] -> {"", ""} end # Parse message header: [leader, fields] = header |> split(["\r\n", "\n"], parts: 2) [method, url, version] = leader |> split(" ", parts: 3) fields = if fields, do: parse_fields fields # Create struct: %HTTPMessage{ url: url, body: body, method: method, version: version, fields: fields } end defp parse_fields(fields) do fields |> split(["\r\n", "\n"]) |> Enum.map(fn (field) -> case split(field, ":", parts: 2) do [name, value] -> {name, trim value} other -> other end end) end def create(message) do %HTTPMessage{ method: method, url: url, version: version, fields: fields, body: body } = message # Convert struct values to string (if not already): method = to_string method url = to_string url version = to_string version body = to_string body fields = to_string create_fields fields # Create HTTP message from the struct values: method <> " " <> url <> " " <> version <> "\r\n" <> fields <> "\r\n\r\n" <> body end defp create_fields(fields) do fields |> Enum.map(fn (field) -> elem(field, 0) <> ": " <> to_string(elem(field, 1)) end) |> Enum.join("\r\n") end end