# NGINX module configuration file
# This file is used by NGINX's ./configure script to build the module

ngx_addon_name=ngx_http_markdown_filter_module

# Resolve Rust converter static library path. Prefer an explicit or inferred
# target triple so we do not accidentally link a cached artifact for the wrong
# libc/architecture (for example musl builds picking a GNU archive).
ngx_markdown_rust_lib=

if [ -n "$RUST_TARGET" ]; then
    ngx_markdown_rust_lib="$ngx_addon_dir/../rust-converter/target/$RUST_TARGET/release/libnginx_markdown_converter.a"
    if [ ! -f "$ngx_markdown_rust_lib" ]; then
        echo "configuration error: RUST_TARGET=$RUST_TARGET was set explicitly but" >&2
        echo "  $ngx_markdown_rust_lib does not exist." >&2
        echo "  Refusing to fall back to a host-platform archive that does not" >&2
        echo "  match the requested target." >&2
        exit 1
    fi
fi

if [ -z "$ngx_markdown_rust_lib" ] || [ ! -f "$ngx_markdown_rust_lib" ]; then
    ngx_markdown_uname_s=$(uname -s 2>/dev/null || echo unknown)
    ngx_markdown_uname_m=$(uname -m 2>/dev/null || echo unknown)
    ngx_markdown_libc=gnu

    if [ "$ngx_markdown_uname_s" = "Linux" ]; then
        if command -v ldd >/dev/null 2>&1; then
            if ldd --version 2>&1 | grep -qi musl || ldd /bin/sh 2>&1 | grep -qi musl; then
                ngx_markdown_libc=musl
            fi
        fi

        case "$ngx_markdown_uname_m:$ngx_markdown_libc" in
            aarch64:musl)
                ngx_markdown_target=aarch64-unknown-linux-musl
                ;;
            aarch64:gnu)
                ngx_markdown_target=aarch64-unknown-linux-gnu
                ;;
            x86_64:musl)
                ngx_markdown_target=x86_64-unknown-linux-musl
                ;;
            x86_64:gnu)
                ngx_markdown_target=x86_64-unknown-linux-gnu
                ;;
        esac
    elif [ "$ngx_markdown_uname_s" = "Darwin" ]; then
        case "$ngx_markdown_uname_m" in
            arm64)
                ngx_markdown_target=aarch64-apple-darwin
                ;;
            x86_64)
                ngx_markdown_target=x86_64-apple-darwin
                ;;
        esac
    fi

    if [ -n "$ngx_markdown_target" ]; then
        ngx_markdown_rust_lib="$ngx_addon_dir/../rust-converter/target/$ngx_markdown_target/release/libnginx_markdown_converter.a"
    fi
fi

if [ ! -f "$ngx_markdown_rust_lib" ]; then
    # Fall back to an existing release archive only when its target triple
    # matches the current platform: a shared repo checkout (e.g. a mounted
    # volume in a container, or a multi-arch local build) may contain
    # archives for other platforms, and the first glob hit could otherwise
    # select a foreign archive (macOS .a inside a Linux build, etc.).
    ngx_markdown_uname_s=$(uname -s 2>/dev/null || echo unknown)
    ngx_markdown_uname_m=$(uname -m 2>/dev/null || echo unknown)
    case "$ngx_markdown_uname_s:$ngx_markdown_uname_m" in
        Linux:aarch64)   ngx_markdown_platform_glob="aarch64-unknown-linux-$ngx_markdown_libc" ;;
        Linux:x86_64)    ngx_markdown_platform_glob="x86_64-unknown-linux-$ngx_markdown_libc" ;;
        Darwin:arm64)    ngx_markdown_platform_glob="aarch64-apple-darwin" ;;
        Darwin:x86_64)   ngx_markdown_platform_glob="x86_64-apple-darwin" ;;
        *)               ngx_markdown_platform_glob="" ;;
    esac
    if [ -n "$ngx_markdown_platform_glob" ]; then
        for candidate in "$ngx_addon_dir"/../rust-converter/target/$ngx_markdown_platform_glob/release/libnginx_markdown_converter.a; do
            if [ -f "$candidate" ]; then
                ngx_markdown_rust_lib="$candidate"
                break
            fi
        done
    fi
fi

if [ -z "$ngx_markdown_rust_lib" ] || [ ! -f "$ngx_markdown_rust_lib" ]; then
    echo "configuration error: cannot locate the Rust converter static library" >&2
    echo "  (libnginx_markdown_converter.a) for platform: $(uname -s 2>/dev/null || echo unknown)/$(uname -m 2>/dev/null || echo unknown)" >&2
    echo "  Build the Rust library first with the module Makefile:" >&2
    echo "    make rust-lib   (uses --target \$(RUST_TARGET) and writes target/<triple>/release/)" >&2
    echo "  or set RUST_TARGET=<triple> to select an existing archive explicitly." >&2
    echo "  Refusing to fall back to an arbitrary target/release archive that may" >&2
    echo "  belong to a different platform." >&2
    exit 1
fi

# Libraries required by the Rust FFI converter.
# Use ngx_module_libs so dynamic-module builds link them into the module .so.
if [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then
    ngx_module_libs="$ngx_markdown_rust_lib -lpthread -lm"
else
    ngx_module_libs="$ngx_markdown_rust_lib -lpthread -ldl -lm"
fi

# Detect arc4random_buf() for cryptographically secure random bytes.
# Available on BSD/macOS natively and Linux glibc >= 2.36.
# When available, prefer it over /dev/urandom (no fd management).
if echo "#include <stdlib.h>" | ${CC:-cc} -x c - -E >/dev/null 2>&1; then
    if echo '#include <stdlib.h>
int main(void) { unsigned char buf[1]; arc4random_buf(buf, 1); return 0; }' \
       | ${CC:-cc} -x c - -o /dev/null >/dev/null 2>&1; then
        CFLAGS="$CFLAGS -DNGX_HAVE_ARC4RANDOM=1"
    fi
fi

# Brotli streaming decompression detection.
# NGX_MARKDOWN_BROTLI_STREAMING=auto|on|off (default: auto)
# When on/auto, probe for <brotli/decode.h> and libbrotlidec; on success
# define NGX_HTTP_BROTLI and link the decoder library.
# On-mode probe failure is a configuration error; auto-mode probe failure falls
# back to bounded full-buffer decompression.
ngx_markdown_brotli_mode=${NGX_MARKDOWN_BROTLI_STREAMING:-auto}

case "$ngx_markdown_brotli_mode" in
    auto|on|off)
        ;;
    *)
        echo "configuration error: invalid NGX_MARKDOWN_BROTLI_STREAMING='$ngx_markdown_brotli_mode'" >&2
        echo "  valid values: auto, on, off" >&2
        exit 1
        ;;
esac

ngx_markdown_brotli_found=no
ngx_markdown_brotli_cflags=
ngx_markdown_brotli_libs=

if [ "$ngx_markdown_brotli_mode" != "off" ]; then
    # Resolve candidate flags with pkg-config, then prove that the compiler
    # can include the header and link the decoder. Metadata alone is not a
    # sufficient build capability check.
    if command -v pkg-config >/dev/null 2>&1 \
       && pkg-config --exists libbrotlidec 2>/dev/null; then
        ngx_markdown_brotli_cflags=$(pkg-config --cflags libbrotlidec 2>/dev/null)
        ngx_markdown_brotli_libs=$(pkg-config --libs libbrotlidec 2>/dev/null)
    else
        ngx_markdown_brotli_libs="-lbrotlidec"
    fi

    ngx_markdown_brotli_test='
#include <brotli/decode.h>
int main(void) {
    BrotliDecoderState *s = BrotliDecoderCreateInstance(0, 0, 0);
    if (s) BrotliDecoderDestroyInstance(s);
    return 0;
}'
    if echo "$ngx_markdown_brotli_test" \
       | ${CC:-cc} $ngx_markdown_brotli_cflags -x c - -o /dev/null \
           $ngx_markdown_brotli_libs >/dev/null 2>&1; then
        ngx_markdown_brotli_found=yes
    fi

    if [ "$ngx_markdown_brotli_found" = "yes" ]; then
        CFLAGS="$CFLAGS -DNGX_HTTP_BROTLI${ngx_markdown_brotli_cflags:+ $ngx_markdown_brotli_cflags}"
        ngx_module_libs="$ngx_module_libs $ngx_markdown_brotli_libs"
    elif [ "$ngx_markdown_brotli_mode" = "on" ]; then
        echo "configuration error: NGX_MARKDOWN_BROTLI_STREAMING=on but libbrotlidec" >&2
        echo "  was not found. Install libbrotli-dev (Debian/Ubuntu) or" >&2
        echo "  brotli-devel (RHEL/Fedora), or ensure pkg-config can find libbrotlidec." >&2
        exit 1
    fi
fi

# Keep the C compilation surface aligned with the Cargo feature set explicitly.
# Rust 1.97 uses LLVM 22, whose LTO archives are not guaranteed to be readable
# by the system nm.  Symbol probing can therefore silently disable matching C
# paths even though the Rust exports are present.  The contract accepts Cargo
# feature names as a comma-separated list, plus the canonical `default` and
# `none` values.  An unset value means Cargo defaults.
ngx_markdown_rust_features=${NGX_MARKDOWN_RUST_FEATURES-default}

case "$ngx_markdown_rust_features" in
    default)
        ngx_markdown_rust_features=prune_noise_regions,streaming
        ;;
    none)
        ngx_markdown_rust_features=
        ;;
    ""|,*|*,|*,,*|*[!a-z_,]*)
        echo "configuration error: invalid NGX_MARKDOWN_RUST_FEATURES='$ngx_markdown_rust_features'" >&2
        exit 1
        ;;
    *)
        ngx_markdown_remaining_features=$ngx_markdown_rust_features
        while test -n "$ngx_markdown_remaining_features"; do
            ngx_markdown_feature=${ngx_markdown_remaining_features%%,*}
            if test "$ngx_markdown_feature" = "$ngx_markdown_remaining_features"; then
                ngx_markdown_remaining_features=
            else
                ngx_markdown_remaining_features=${ngx_markdown_remaining_features#*,}
            fi

            case "$ngx_markdown_feature" in
                streaming|prune_noise_regions)
                    ;;
                *)
                    echo "configuration error: invalid NGX_MARKDOWN_RUST_FEATURES='$NGX_MARKDOWN_RUST_FEATURES'" >&2
                    exit 1
                    ;;
            esac
        done
        ;;
esac

case ",$ngx_markdown_rust_features," in
    *,streaming,*)
        CFLAGS="$CFLAGS -DMARKDOWN_STREAMING_ENABLED"
        ;;
esac

# Embed an explicit build identity in the module diagnostics document.  Local
# builds use a deliberately non-release identity; release builds must supply
# the exact source, Rust compiler, and feature-manifest identity from the
# immutable build inputs.
ngx_markdown_build_kind=${NGX_MARKDOWN_BUILD_KIND-development}
ngx_markdown_source_sha=${NGX_MARKDOWN_SOURCE_SHA-development}
ngx_markdown_rust_version=${NGX_MARKDOWN_RUST_VERSION-development}
ngx_markdown_feature_manifest_digest=${NGX_MARKDOWN_FEATURE_MANIFEST_DIGEST-development}

case "$ngx_markdown_build_kind" in
    development)
        if test "$ngx_markdown_source_sha" != development \
           || test "$ngx_markdown_rust_version" != development \
           || test "$ngx_markdown_feature_manifest_digest" != development; then
            echo "configuration error: development builds must use the development build identity" >&2
            exit 1
        fi
        ;;
    release)
        if ! printf '%s\n' "$ngx_markdown_source_sha" \
            | grep -Eq '^[0-9a-f]{40}$'; then
            echo "configuration error: release source SHA must be a 40-character lowercase hex value" >&2
            exit 1
        fi
        if ! printf '%s\n' "$ngx_markdown_rust_version" \
            | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then
            echo "configuration error: release Rust version must be normalized semver" >&2
            exit 1
        fi
        if ! printf '%s\n' "$ngx_markdown_feature_manifest_digest" \
            | grep -Eq '^sha256:[0-9a-f]{64}$'; then
            echo "configuration error: release feature manifest digest is invalid" >&2
            exit 1
        fi
        if ! command -v rustc >/dev/null 2>&1; then
            echo "configuration error: release builds require rustc to verify the compiler identity" >&2
            exit 1
        fi
        ngx_markdown_rustc_version=$(rustc -Vv 2>/dev/null \
            | sed -n 's/^release: //p')
        if test "$ngx_markdown_rustc_version" != "$ngx_markdown_rust_version"; then
            echo "configuration error: configured Rust version does not match rustc -Vv" >&2
            exit 1
        fi
        ;;
    *)
        echo "configuration error: NGX_MARKDOWN_BUILD_KIND must be development or release" >&2
        exit 1
        ;;
esac

ngx_markdown_define_string() {
    CFLAGS="$CFLAGS -D$1=\\\"$2\\\""
}

ngx_markdown_define_string NGX_HTTP_MARKDOWN_BUILD_KIND \
    "$ngx_markdown_build_kind"
ngx_markdown_define_string NGX_HTTP_MARKDOWN_SOURCE_SHA \
    "$ngx_markdown_source_sha"
ngx_markdown_define_string NGX_HTTP_MARKDOWN_RUST_VERSION \
    "$ngx_markdown_rust_version"
ngx_markdown_define_string NGX_HTTP_MARKDOWN_FEATURE_MANIFEST_DIGEST \
    "$ngx_markdown_feature_manifest_digest"

case ",$ngx_markdown_rust_features," in
    *,prune_noise_regions,*)
        CFLAGS="$CFLAGS -DMARKDOWN_PRUNE_NOISE_ENABLED"
        ;;
esac

# Register separate header and body filter hooks.  NGINX uses one module-array
# order for both hooks, but the header hook must run before not_modified while
# the body hook must run after copy_filter has materialized file buffers.
if test -n "$ngx_module_link"; then
    ngx_module_type=HTTP_AUX_FILTER
    if test "$ngx_module_link" = DYNAMIC; then
        # Keep the primary name first so the dynamic artifact retains the
        # established ngx_http_markdown_filter_module.so filename.
        ngx_module_name="$ngx_addon_name \
                         ngx_http_markdown_body_filter_module"
    else
        ngx_module_name=ngx_http_markdown_body_filter_module
    fi

    ngx_module_srcs="$ngx_addon_dir/src/ngx_http_markdown_filter_module.c \
                     $ngx_addon_dir/src/ngx_http_markdown_accept.c \
                     $ngx_addon_dir/src/ngx_http_markdown_auth.c \
                     $ngx_addon_dir/src/ngx_http_markdown_buffer.c \
                     $ngx_addon_dir/src/ngx_http_markdown_eligibility.c \
                     $ngx_addon_dir/src/ngx_http_markdown_error.c \
                     $ngx_addon_dir/src/ngx_http_markdown_headers.c \
                     $ngx_addon_dir/src/ngx_http_markdown_header_plan.c \
                     $ngx_addon_dir/src/ngx_http_markdown_conditional.c \
                     $ngx_addon_dir/src/ngx_http_markdown_decompression.c \
                     $ngx_addon_dir/src/ngx_http_markdown_reason.c \
                     $ngx_addon_dir/src/ngx_http_markdown_reason_ffi.c \
                     $ngx_addon_dir/src/ngx_http_markdown_diagnostics_reason.c \
                     $ngx_addon_dir/src/ngx_http_markdown_diagnostics.c \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_replay.c \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_commit.c \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_postcommit.c"
    ngx_module_deps="$ngx_addon_dir/src/ngx_http_markdown_filter_module.h \
                     $ngx_addon_dir/src/ngx_http_markdown_header_plan.h \
                     $ngx_addon_dir/src/ngx_http_markdown_diagnostics.h \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_replay.h \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_commit.h \
                     $ngx_addon_dir/src/ngx_http_markdown_stream_postcommit.h"

    if test "$ngx_module_link" = DYNAMIC; then
        # Header filters are initialized in module-array order but run in the
        # reverse order.  Keep the body hook before copy_filter in the array
        # and the header hook after not_modified.  Keeping slice after the
        # header hook preserves the core filter order when it is available.
        ngx_module_order="ngx_http_markdown_body_filter_module \
                          ngx_http_copy_filter_module \
                          $ngx_addon_name \
                          ngx_http_slice_filter_module"

        . auto/module
    else
        # Static addons are accumulated by module type.  Place the body hook
        # in the auxiliary group and the header hook in the final core-filter
        # group to give the two hooks their independent runtime positions.
        . auto/module
        ngx_module_type=HTTP_INIT_FILTER
        ngx_module_name=$ngx_addon_name
        . auto/module
    fi
else
    # Static module
    # Keep compatibility with older NGINX configure scripts while preserving
    # the independent body/header filter positions.
    HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES \
                            ngx_http_markdown_body_filter_module"
    HTTP_INIT_FILTER_MODULES="$HTTP_INIT_FILTER_MODULES $ngx_addon_name"
    NGX_ADDON_SRCS="$NGX_ADDON_SRCS \
                    $ngx_addon_dir/src/ngx_http_markdown_filter_module.c \
                    $ngx_addon_dir/src/ngx_http_markdown_accept.c \
                    $ngx_addon_dir/src/ngx_http_markdown_auth.c \
                    $ngx_addon_dir/src/ngx_http_markdown_buffer.c \
                    $ngx_addon_dir/src/ngx_http_markdown_eligibility.c \
                    $ngx_addon_dir/src/ngx_http_markdown_error.c \
                    $ngx_addon_dir/src/ngx_http_markdown_headers.c \
                    $ngx_addon_dir/src/ngx_http_markdown_header_plan.c \
                    $ngx_addon_dir/src/ngx_http_markdown_conditional.c \
                    $ngx_addon_dir/src/ngx_http_markdown_decompression.c \
                    $ngx_addon_dir/src/ngx_http_markdown_reason.c \
                    $ngx_addon_dir/src/ngx_http_markdown_reason_ffi.c \
                    $ngx_addon_dir/src/ngx_http_markdown_diagnostics_reason.c \
                    $ngx_addon_dir/src/ngx_http_markdown_diagnostics.c \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_replay.c \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_commit.c \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_postcommit.c"
    NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_addon_dir/src/ngx_http_markdown_filter_module.h \
                    $ngx_addon_dir/src/ngx_http_markdown_header_plan.h \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_replay.h \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_commit.h \
                    $ngx_addon_dir/src/ngx_http_markdown_stream_postcommit.h \
                    $ngx_addon_dir/src/ngx_http_markdown_diagnostics.h"
fi

# Note: ngx_module_libs is consumed by NGINX's auto/module logic for both
# dynamic-module and static-module builds. Avoid writing directly to CORE_LIBS
# here, or dynamic-module builds will miss the Rust FFI symbols at runtime.
