[go: up one dir, main page]

Using page aliases combined with the indexify style leads to redirect loops

Normally, page aliases in Antora are used to resolve outdated links without causing issues. However, with indexify, the same URL may inadvertently be used for both the source and target of a redirect, leading to loops. For example, creating a page alias for modules/manage/security/authorization.adoc to point to modules/manage/security/authorization/index.adoc can lead to a redirect loop where manage/security/authorization/ points to manage/security/authorization/.

Currently, Antora does not seem to check if the alias results in a URL that is identical to the target page’s URL.

Proposed Solution:

Update methods in produceRedirects() to skip aliases that lead to redirect loops:

function isRedirectLoop (file) {
  if (file.pub.url === file.rel.pub.url) return true
  return false
}

function createHttpdHtaccess (files, urlPath, directoryRedirects = false) {
  const rules = files.reduce((accum, file) => {
    if (isRedirectLoop(file)) return accum
    delete file.out
    let fromUrl = file.pub.url
    fromUrl = ~fromUrl.indexOf('%20') ? `'${urlPath}${fromUrl.replace(ENCODED_SPACE_RX, ' ')}'` : urlPath + fromUrl
    let toUrl = file.rel.pub.url
    toUrl = ~toUrl.indexOf('%20') ? `'${urlPath}${toUrl.replace(ENCODED_SPACE_RX, ' ')}'` : urlPath + toUrl
    // see https://httpd.apache.org/docs/current/en/mod/mod_alias.html#redirect
    // NOTE: redirect rule for directory prefix does not require trailing slash
    if (file.pub.splat) {
      accum.push(`Redirect 302 ${fromUrl} ${stripTrailingSlash(toUrl)}`)
    } else if (directoryRedirects) {
      accum.push(`RedirectMatch 301 ^${regexpEscape(fromUrl)}$ ${stripTrailingSlash(toUrl)}`)
    } else {
      accum.push(`Redirect 301 ${fromUrl} ${toUrl}`)
    }
    return accum
  }, [])
  return [new File({ contents: Buffer.from(rules.join('\n') + '\n'), out: { path: '.htaccess' } })]
}

// NOTE: a trailing slash on the pathname will be ignored
// see https://docs.netlify.com/routing/redirects/redirect-options/#trailing-slash
// however, we keep it when generating the rules for clarity
function createNetlifyRedirects (files, urlPath, addDirectoryRedirects = false, useForceFlag = true) {
  const rules = files.reduce((accum, file) => {
    if (isRedirectLoop(file)) return accum
    delete file.out
    const fromUrl = urlPath + file.pub.url
    const toUrl = urlPath + file.rel.pub.url
    const forceFlag = useForceFlag ? '!' : ''
    if (file.pub.splat) {
      accum.push(`${fromUrl}/* ${ensureTrailingSlash(toUrl)}:splat 302${forceFlag}`)
    } else {
      accum.push(`${fromUrl} ${toUrl} 301${forceFlag}`)
      if (addDirectoryRedirects && fromUrl.endsWith('/index.html')) {
        accum.push(`${fromUrl.substr(0, fromUrl.length - 10)} ${toUrl} 301${forceFlag}`)
      }
    }
    return accum
  }, [])
  return [new File({ contents: Buffer.from(rules.join('\n') + '\n'), out: { path: '_redirects' } })]
}

function createNginxRewriteConf (files, urlPath) {
  const rules = files.map((file) => {
    if (isRedirectLoop(file)) return ''
    delete file.out
    let fromUrl = file.pub.url
    fromUrl = ~fromUrl.indexOf('%20') ? `'${urlPath}${fromUrl.replace(ENCODED_SPACE_RX, ' ')}'` : urlPath + fromUrl
    let toUrl = file.rel.pub.url
    toUrl = ~toUrl.indexOf('%20') ? `'${urlPath}${toUrl.replace(ENCODED_SPACE_RX, ' ')}'` : urlPath + toUrl
    if (file.pub.splat) {
      const toUrlWithTrailingSlash = ensureTrailingSlash(toUrl)
      return `location ^~ ${fromUrl}/ { rewrite ^${regexpEscape(fromUrl)}/(.*)$ ${toUrlWithTrailingSlash}$1 redirect; }`
    } else {
      return `location = ${fromUrl} { return 301 ${toUrl}; }`
    }
  })
  return [new File({ contents: Buffer.from(rules.join('\n').trim() + '\n'), out: { path: '.etc/nginx/rewrite.conf' } })]
}

function populateStaticRedirectFiles(files, siteUrl) {
  for (const file of files) {
    if (isRedirectLoop(file)) continue
    const content = createStaticRedirectContents(file, siteUrl) + '\n';
    file.contents = Buffer.from(content);
  }
  return []
}
Edited by Jake Cahill