package openresty import ( "fmt" "strconv" "strings" ) const ( // OriginErrorPageSupportPath is the SupportFile path for the origin error HTML template. OriginErrorPageSupportPath = "error_pages/origin_error.html.tmpl" // OriginErrorPageInternalLocation is the internal nginx location that serves the error body. OriginErrorPageInternalLocation = "/__openflare_origin_error" defaultOriginErrorPageStatusTag = "500-599" ) // DefaultOriginErrorPageHTML is the built-in default (aligned with frontend minimalist). // Placeholders {{status}} and {{host}} are substituted at request time by Lua. const DefaultOriginErrorPageHTML = ` {{status}} | OpenFlare

{{status}}

The upstream server is unreachable. Please try again later or contact the site administrator if the problem persists.

{{host}}

` // EffectiveOriginErrorPageHTML returns custom HTML when set, otherwise the built-in default. func EffectiveOriginErrorPageHTML(cfg ConfigSnapshot) string { if strings.TrimSpace(cfg.OriginErrorPageHTML) == "" { return DefaultOriginErrorPageHTML } return cfg.OriginErrorPageHTML } func effectiveOriginErrorPageStatusTags(cfg ConfigSnapshot) []string { if len(cfg.OriginErrorPageStatusCodes) == 0 { return []string{defaultOriginErrorPageStatusTag} } return cfg.OriginErrorPageStatusCodes } func originErrorPageSupportFile(cfg ConfigSnapshot) SupportFile { return SupportFile{ Path: OriginErrorPageSupportPath, Content: EffectiveOriginErrorPageHTML(cfg), } } func renderOriginErrorPageIntercept(cfg ConfigSnapshot) string { if !cfg.OriginErrorPageEnabled { return "" } if _, err := ExpandStatusCodeTags(effectiveOriginErrorPageStatusTags(cfg)); err != nil { return "" } return " proxy_intercept_errors on;\n" } // renderOriginErrorPageServerBits emits server-level error_page + internal location. // Returns empty string when disabled, expand fails, or no codes remain. func renderOriginErrorPageServerBits(cfg ConfigSnapshot) string { if !cfg.OriginErrorPageEnabled { return "" } codes, err := ExpandStatusCodeTags(effectiveOriginErrorPageStatusTags(cfg)) if err != nil || len(codes) == 0 { return "" } parts := make([]string, len(codes)) for i, code := range codes { parts[i] = strconv.Itoa(code) } var builder strings.Builder fmt.Fprintf(&builder, " error_page %s = %s;\n", strings.Join(parts, " "), OriginErrorPageInternalLocation) builder.WriteString(renderOriginErrorPageInternalLocation()) return builder.String() } func renderOriginErrorPageInternalLocation() string { return fmt.Sprintf(` location = %s { internal; default_type text/html; charset utf-8; content_by_lua_block { local f = io.open("%s", "r") if not f then ngx.status = ngx.status ngx.say("Error ", ngx.status) return end local body = f:read("*a") f:close() local status = tostring(ngx.status) local host = ngx.var.host or "" body = body:gsub("{{status}}", status, 1) body = body:gsub("{{host}}", host, 1) body = body:gsub("{{status}}", status) body = body:gsub("{{host}}", host) ngx.header["Content-Type"] = "text/html; charset=utf-8" ngx.say(body) } } `, OriginErrorPageInternalLocation, ErrorPageTmplPlaceholder) }