Preventing mod_cfml redirect from hitting client

We’re using mod_cfml to dynamically configure contexts in Tomcat for Lucee. When an initial request is made to an unknown host, mod_cfml will return a redirect status code, which we have configured for 307.

Is there anyway to get Apache/Nginx to retry these operations instead of passing it back to the client?

It would seem like maybe there should be a way to get a proxied request to re-issue a retry to itself, but maybe it’s just a bad idea.

We have some code in a few places that do HTTP calls to the application and we’re currently not following redirects, because a 302 redirect is a sign of a problem. I could fix that code to retry for 307 error codes, but I’m afraid the issue could cause problems with API calls outside our organization where people are connecting. I could add a warm up script to hit all domains after Tomcat is started, but I was hoping there might be a way to just prevent the issue at all or at least prevent the client from seeing the problem.

I’m wondering if something like this might work for Nginx:

FWIW, CommandBox 5.5 has mod cfml support built in and it doesn’t use a redirect. I creates the context on the fly and then immediately uses it :slight_smile:

1 Like

Yes, it will work with NGINX

Thanks for the reply. Do you by any chance have a working example which you’re using?

In nginx you would use

return (307) url;

A better example would be

server {
    ...

    location / {
        proxy_pass http://backend;
        proxy_intercept_errors on;
        error_page 307 = @handle_redirect;
    }

    location @handle_redirect {
        set $saved_redirect_location '$upstream_http_location';
        proxy_pass $saved_redirect_location;
    }
}

in Apache you have mod_proxy
<Proxy balancer://foo_com>
BalancerMember http://www1.foo.com:8080
BalancerMember http://www2.foo.com:8080 loadfactor=2 timeout=1
BalancerMember http://www3.foo.com:8080 status=+R
BalancerMember http://www4.foo.com:8080 status=+R
ProxySet lbmethod=byrequests

@Terry_Whitney,

Thanks for the example code. After a lot of trial and error, here’s what I ultimately went with:

First, I modified my Tomcat’s server.xml so that the mod_cfml module would return a 306 HTTP Status code when the context is created. I choose 306 because Nginx only seems to support status codes 308 and earlier for redirection and while 306 is depreciated, it meant Switch Proxy, so that felt logical. Also, our application would never use a 306 HTTP status code, so the only time this should be generated is when mod_cfml is creating the context.

Here’s what I put in the server.xml file:

<Valve className="mod_cfml.core"
       loggingEnabled="false"
       maxContexts="200"
       timeBetweenContexts="2000"
       scanClassPaths="false"
       responseCode="306"
       sharedKey="{{SHARED-KEY-HERE}}"
/>

Next, I updated my Nginx configurations with the following:

location ~* (\.cfm(\/|$)|\.cfc$) {
	# if mod_cfml has intercepted the request to create the context, we need to replay the request
	proxy_intercept_errors on;
	error_page 306 = @handle_lucee_mod_cfml_init_redirect;

	include conf.lib/lucee-app-proxy.conf;
}

location @handle_lucee_mod_cfml_init_redirect {
	# if we have a path_info string parsed, we must supply it back when we retry the request
	# so that the full URL is correctly parsed
	if ($pathinfo != false ) {
		rewrite (^.+$) $1$pathinfo break;
	}

	# this will allow us to replay the redirect event
	include conf.lib/lucee-app-proxy.conf;
}

The first location function monitors for all CFM/CFC pages and passes it to our proxy configuration (i.e. conf.lib/lucee-app-proxy.conf). If the proxy returns the 306 status code, then the request is redirected to the @handle_lucee_mod_cfml_init_redirect and the proxy is hit again.

This seems to work exactly like I want, so that the client requests do not have to perform the redirect and it’s all handled before the request is returned.

Thanks again for getting me on the right path!

3 Likes