Course outline

Apache HTTPD / Representation, proxying, and capacity / Lesson 8

Redirects, internal rewriting, and rule context

Use the simplest supported mapping contract and preserve method, query, and loop semantics deliberately.

About 4 min readContent reviewed
On this page

Lesson goals

  • Distinguish a client redirect from internal resource mapping.
  • Explain server versus per-directory RewriteRule matching scope.

A redirect changes the client’s next request

A redirect sends a response instructing the client to request another URL. An internal rewrite changes server-side mapping without necessarily changing the browser address. Parcel’s legacy documentation link can need a redirect, while an application front controller can need internal mapping. They have different cache, method, visibility, and authorization consequences. Prefer a simple supported directive when it expresses the intended behavior clearly. Powerful rewriting is not automatically a better solution than Alias, Redirect, or a well-defined application route.

The same pattern can mean something different elsewhere

mod_rewrite uses documented matching rules and PCRE-based regular expressions. Server or virtual-host context differs from per-directory and .htaccess context, where directory prefixes are stripped and leading-slash assumptions change. Substitutions can be processed again through internal request handling, and flags determine important continuation behavior. Copying a rule into another context is therefore a behavior change, not a formatting edit. Review decoded path, query handling, conditions, target form, module support, and selected 2.4 patch requirements before relying on a rule.

Read one exact server-context redirect

The fragment below is explicitly for server or virtual-host context and redirects the exact /legacy path to /docs/ with a temporary status. It is never loaded and is not an .htaccess example. No request is sent. The choice of status is a teaching decision, not a universal production policy; permanent caching and method-preservation requirements must be reviewed for the real route. Query behavior and target authority remain explicit review topics rather than assumptions hidden in a short rule.

apache A non-runnable exact-path redirect fragment
RewriteEngine On
RewriteRule "^/legacy$" "/docs/" [R=302,L]

mod_rewrite and appropriate context are required. The fragment does not test encoding, query behavior, nested rewrites, proxy handling, or client cache semantics. It must not be transplanted into per-directory scope unchanged.

A locally reasonable pair can form a redirect loop

One rule can send /legacy to /docs while another inherited rule sends /docs back. Proxy scheme information can also create repeated HTTPS redirects if the effective scheme contract is wrong. Do not fix loops by raising recursion limits or suppressing every redirect. Establish the complete route and rule chain. Untrusted host or path text used to construct an external target can create unintended destinations, so validate target authority and avoid dynamic open-ended forwarding. Preserve relevant sensitive data without copying full query strings into public traces.

Detect a cycle in a declared path graph

The complete local model below follows a two-edge synthetic redirect graph and reports a loop. It is not a PCRE test, mod_rewrite engine, HTTP client, or browser cache simulation. Real rule evaluation includes contexts, conditions, query state, flags, and repeated internal processing beyond this graph. The model illustrates why reviewing individual lines is insufficient. A separately authorized validation plan should include normal, unmatched, trailing-slash, query, method, and loop cases without assuming one successful request proves the whole routing contract.

python A synthetic redirect-cycle check
redirects = {"/legacy": "/docs/", "/docs/": "/legacy"}
seen = set()
path = "/legacy"
while path in redirects and path not in seen:
    seen.add(path)
    path = redirects[path]
print("loop" if path in seen else "finished")
print(sorted(seen))
Expected output
loop
['/docs/', '/legacy']

Only declared path strings are traversed. No URL is requested, rule compiled, server invoked, or redirect cached.

Common errors and fixes

A server-context leading-slash rule is copied directly into .htaccess.

Why it happens
The matching prefix and evaluation context changed.
How to fix it
Rewrite the rule for its documented scope and validate representative cases.
Prevent it next time
Keep context and assumptions beside each rule.

A permanent redirect is used without reviewing client caching and method behavior.

Why it happens
A status code is chosen as a generic success response.
How to fix it
Choose semantics for the actual migration and client contract.
Prevent it next time
Review redirect lifetime, method, and target scope explicitly.

Two individually plausible rules create a loop.

Why it happens
Only isolated lines were reviewed rather than the effective chain.
How to fix it
Trace the full mapping and scheme path and correct the conflicting intent.
Prevent it next time
Include cycle and unmatched cases in routing review.

Check your understanding

1. Why does the shown rule not claim to work unchanged in .htaccess?

Show worked solution

Per-directory matching strips a directory prefix and changes leading-slash assumptions. The exact rule belongs to its declared server or virtual-host context. Review documented per-directory semantics and the effective include scope before adapting it.

2. Does the Python loop detector prove that an Apache redirect chain is loop-free?

Show worked solution

No. It checks one declared graph only and actually demonstrates a cycle. Apache conditions, encodings, flags, internal requests, query state, and client behavior are outside the model. Actual route validation requires an authorized suitable process.

Key takeaways

  • Redirect and internal rewrite have different client and lifecycle effects.
  • Rule context and the complete chain determine behavior.

Official references