Configuration: HTTP map

This page documents the map directive. It creates variables whose values come from matching a source variable against a set of patterns. Mapped variables are available via {{variable}} interpolation in other directives.

Important

map belongs in HTTP scope. Put it in an http * block, a host block, or a location block. It has no effect in the bare global { ... } block. The global block holds server-wide settings, not per-request HTTP directives. When you migrate from NGINX, http * is the counterpart of the NGINX http context.

Directives⁠#

map⁠#

  • map <source: string> <destination: string>
    • This directive specifies a source variable to match and a destination variable name to create. The nested block defines the mapping rules. Default: none
Note

The destination variable name can be any identifier. Ferron stores it in the request variable map. You access it via {{name}} interpolation.

Block sub-directives⁠#

Sub-directiveArgumentsDescriptionDefault
default<value: string>The fallback value when no entry matches the source.Empty string
exact<pattern: string> <result: string>Exact string match, or wildcard match if the pattern contains *.None
regex<pattern: string> <result: string>Regular expression match. You can reference capture groups in the result as $1, $2, and so onNone
Note

If Ferron cannot resolve the source variable, it treats the source value as an empty string and uses the default value. Ferron compiles regex patterns at parse time. It rejects invalid patterns during validation. Ferron converts wildcard patterns (*) to regex internally.

Tip

Values can also contain variable interpolations ({{name}}) that Ferron resolves at runtime.

Block options (inside regex { ... })⁠#

OptionArgumentsDescriptionDefault
case_insensitive<bool>When true, Ferron matches the regular expression pattern case-insensitively.false

Configuration example:

http * {
    map request.uri.path category {
        default uncategorized
        exact /api/* api
        exact /blog/* blog
    }
}

Matching priority⁠#

When Ferron evaluates a map block, it checks the entries in this order:

  1. Exact match: the source value equals the pattern string exactly.
  2. Wildcard match: the pattern contains * which matches any characters (equivalent to .* in regex). The longest-matching wildcard wins.
  3. Regex match: the first regular expression in declaration order that matches the source value.
  4. Default: the default value, or an empty string if not specified.

Simple variable mapping⁠#

http * {
    map request.uri.path category {
        default uncategorized
        exact /api/* api
        exact /blog/* blog
        exact /docs docs
    }
}

example.com {
    location / {
        proxy http://backend {
            request_header X-Category "{{category}}"
        }
    }
}

Requests to /api/users set category to api, requests to /blog/post set it to blog, and /docs sets it to docs. Everything else falls back to uncategorized. Ferron then passes the mapped variable to the backend as a header.

Regex with capture groups⁠#

http * {
    map request.uri.path user_id {
        default ""
        regex "^/users/([0-9]+)" "$1"
    }
}

A request to /users/42 sets user_id to 42. Capture groups from the regex are available as $1, $2, and so on in the result string. If the pattern has no capture groups or the group does not exist, Ferron keeps the reference literally (for example $1).

Case-insensitive matching⁠#

http * {
    map request.header.user_agent is_mobile {
        default "0"
        regex "mobile" "1" {
            case_insensitive
        }
        regex "android" "1" {
            case_insensitive
        }
    }
}

The case_insensitive option applies to individual regex entries. Alternatively, you can use the inline (?i) flag in the pattern itself: regex "(?i)mobile" "1".

Map at host and location level⁠#

You can define map blocks inside http * blocks, host blocks, and location blocks. They inherit from parent scopes using standard Ferron inheritance. Do not place map in the bare global { ... } block.

http * {
    map request.uri.path site_section {
        default default
        exact /public/* public
    }
}

example.com {
    # Overrides the global map for this host
    map request.uri.path site_section {
        default example-default
        exact /special/* special
    }

    location /admin {
        # Overrides at location level
        map request.uri.path site_section {
            default admin
        }
    }
}

When you define a map with the same destination variable at multiple levels, the innermost scope takes precedence. Ferron evaluates all maps with different destination variables.

Pipeline position⁠#

Map evaluation runs after client IP resolution and before URL rewriting. This means mapped variables are available for use in rewrite patterns, proxy configuration, and other downstream directives.

Info

For map interaction with rewriting, see URL rewriting.

Observability⁠#

Trace spans⁠#

The map stage sets the following attributes on its ferron.stage.map span:

AttributeTypeDescription
ferron.map.variablestringThe variable name that Ferron maps.
ferron.map.editedboolWhether the mapping changed the variable value.