Current section
Files
Jump to
Current section
Files
src/dream@http@header.erl
-module(dream@http@header).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/dream/http/header.gleam").
-export([header_name/1, header_value/1, get_header/2, set_header/3, add_header/3, remove_header/2]).
-export_type([header/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" HTTP header types and utilities\n"
"\n"
" Types and functions for working with HTTP headers. Headers can be used\n"
" with both requests and responses.\n"
"\n"
" ## Common Operations\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" // Create headers\n"
" let headers = [\n"
" Header(\"Content-Type\", \"application/json\"),\n"
" Header(\"Cache-Control\", \"max-age=3600\"),\n"
" ]\n"
"\n"
" // Get a header value\n"
" header.get_header(headers, \"content-type\") // Some(\"application/json\")\n"
"\n"
" // Set or replace a header\n"
" header.set_header(headers, \"X-Custom\", \"value\")\n"
"\n"
" // Add a header without replacing\n"
" header.add_header(headers, \"Set-Cookie\", \"session=abc\")\n"
" ```\n"
).
-type header() :: {header, binary(), binary()}.
-file("src/dream/http/header.gleam", 62).
?DOC(
" Get the name of a header\n"
"\n"
" Extracts the name field from a Header.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let h = Header(\"Content-Type\", \"application/json\")\n"
" header.header_name(h) // \"Content-Type\"\n"
" ```\n"
).
-spec header_name(header()) -> binary().
header_name(Header) ->
case Header of
{header, Name, _} ->
Name
end.
-file("src/dream/http/header.gleam", 80).
?DOC(
" Get the value of a header\n"
"\n"
" Extracts the value field from a Header.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let h = Header(\"Content-Type\", \"application/json\")\n"
" header.header_value(h) // \"application/json\"\n"
" ```\n"
).
-spec header_value(header()) -> binary().
header_value(Header) ->
case Header of
{header, _, Value} ->
Value
end.
-file("src/dream/http/header.gleam", 111).
-spec find_header(list(header()), binary()) -> gleam@option:option(binary()).
find_header(Headers, Normalized_name) ->
case Headers of
[] ->
none;
[{header, Header_name, Value} | Rest] ->
Matches = string:lowercase(Header_name) =:= Normalized_name,
case Matches of
true ->
{some, Value};
false ->
find_header(Rest, Normalized_name)
end
end.
-file("src/dream/http/header.gleam", 106).
?DOC(
" Get the value of a header by name (case-insensitive)\n"
"\n"
" Searches a list of headers for one matching the given name.\n"
" Header name comparison is case-insensitive (\"content-type\" matches \"Content-Type\").\n"
" Returns the first matching header's value.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let headers = [\n"
" Header(\"Content-Type\", \"application/json\"),\n"
" Header(\"Cache-Control\", \"max-age=3600\"),\n"
" ]\n"
"\n"
" header.get_header(headers, \"content-type\") // Some(\"application/json\")\n"
" header.get_header(headers, \"CACHE-CONTROL\") // Some(\"max-age=3600\")\n"
" header.get_header(headers, \"X-Missing\") // None\n"
" ```\n"
).
-spec get_header(list(header()), binary()) -> gleam@option:option(binary()).
get_header(Headers, Name) ->
Normalized_name = string:lowercase(Name),
find_header(Headers, Normalized_name).
-file("src/dream/http/header.gleam", 171).
-spec filter_headers_recursive(list(header()), binary(), list(header())) -> list(header()).
filter_headers_recursive(Headers, Normalized_name, Acc) ->
case Headers of
[] ->
lists:reverse(Acc);
[Header | Rest] ->
Header_normalized = string:lowercase(header_name(Header)),
Should_keep = Header_normalized /= Normalized_name,
case Should_keep of
true ->
filter_headers_recursive(
Rest,
Normalized_name,
[Header | Acc]
);
false ->
filter_headers_recursive(Rest, Normalized_name, Acc)
end
end.
-file("src/dream/http/header.gleam", 164).
-spec filter_matching_headers(list(header()), binary()) -> list(header()).
filter_matching_headers(Headers, Normalized_name) ->
filter_headers_recursive(Headers, Normalized_name, []).
-file("src/dream/http/header.gleam", 154).
?DOC(
" Set or replace a header\n"
"\n"
" If a header with this name exists (case-insensitive), replaces its value.\n"
" If not, adds a new header. Only one header with the given name will exist\n"
" in the result.\n"
"\n"
" Use this when you want to ensure exactly one value for a header (most cases).\n"
" For headers that can appear multiple times (like Set-Cookie), use `add_header` instead.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let headers = [Header(\"Content-Type\", \"text/plain\")]\n"
"\n"
" // Replace existing header\n"
" let updated = header.set_header(headers, \"content-type\", \"application/json\")\n"
" // Result: [Header(\"content-type\", \"application/json\")]\n"
"\n"
" // Add new header\n"
" let with_cache = header.set_header(updated, \"Cache-Control\", \"max-age=3600\")\n"
" // Result: [\n"
" // Header(\"Cache-Control\", \"max-age=3600\"),\n"
" // Header(\"content-type\", \"application/json\")\n"
" // ]\n"
" ```\n"
).
-spec set_header(list(header()), binary(), binary()) -> list(header()).
set_header(Headers, Name, Value) ->
Normalized_name = string:lowercase(Name),
Filtered = filter_matching_headers(Headers, Normalized_name),
[{header, Name, Value} | Filtered].
-file("src/dream/http/header.gleam", 214).
?DOC(
" Add a header without removing existing ones with the same name\n"
"\n"
" Adds a new header even if one with the same name already exists.\n"
" This allows multiple headers with the same name, which is valid for\n"
" some headers like Set-Cookie, Warning, or Accept.\n"
"\n"
" Use this when you need multiple values for the same header name.\n"
" For most headers, use `set_header` instead to ensure only one value.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let headers = []\n"
"\n"
" // Add multiple Set-Cookie headers\n"
" headers\n"
" |> header.add_header(\"Set-Cookie\", \"session=abc; HttpOnly\")\n"
" |> header.add_header(\"Set-Cookie\", \"preferences=dark; Path=/\")\n"
" // Result: [\n"
" // Header(\"Set-Cookie\", \"preferences=dark; Path=/\"),\n"
" // Header(\"Set-Cookie\", \"session=abc; HttpOnly\")\n"
" // ]\n"
" ```\n"
).
-spec add_header(list(header()), binary(), binary()) -> list(header()).
add_header(Headers, Name, Value) ->
[{header, Name, Value} | Headers].
-file("src/dream/http/header.gleam", 244).
?DOC(
" Remove a header by name (case-insensitive)\n"
"\n"
" Removes all headers with the given name (case-insensitive).\n"
" Returns a new list with matching headers filtered out.\n"
"\n"
" ## Example\n"
"\n"
" ```gleam\n"
" import dream/http/header.{Header}\n"
"\n"
" let headers = [\n"
" Header(\"Content-Type\", \"application/json\"),\n"
" Header(\"Cache-Control\", \"max-age=3600\"),\n"
" Header(\"X-Debug\", \"true\"),\n"
" ]\n"
"\n"
" header.remove_header(headers, \"x-debug\")\n"
" // Result: [\n"
" // Header(\"Content-Type\", \"application/json\"),\n"
" // Header(\"Cache-Control\", \"max-age=3600\")\n"
" // ]\n"
" ```\n"
).
-spec remove_header(list(header()), binary()) -> list(header()).
remove_header(Headers, Name) ->
Normalized_name = string:lowercase(Name),
filter_matching_headers(Headers, Normalized_name).