IIS URL Rewrite Config for FW/1 SES

SES_Screen_ShotAfter a bit of research, I was never able to find a definitive answer as how to properly set up SES (Search Engine Safe URL’s) to work with FW/1 (Framework 1) using IIS 7.5 and IIS URL Rewrite 2.0.

SES makes turns your URL’s from this:

http://www.mysite.com/index.cfm?action=main.default&ID=0

Into this:

http://www.mysite.com/main/default/ID/0

First of all you may need to install URL Rewrite 2.0 using Microsoft Web Platform Installer. There are other options out there, but I’m using this since it’s simple and nicely integrated.

From the URL Rewrite options screen, add a new rule and select “User-friendly URL” under the “Inbound and Outbound Rules”.

The requested URL should match the pattern using regular expressions. The pattern being:

^(.*)$

Add the conditions that the type is not a file or a directory.

The action type is rewrite and the rewrite URL is:

/index.cfm/{R:1}

Be sure to check “Append query string” and “Stop processing of subsequent rules”

Continue reading

#coldfusion-2, #fw1, #iis, #microsoft-web-platform-installer

FW/1 SES w/ IIS 7.5 URL Rewrite

I am trying to implement REST with ColdFusion FW/1. However I was always getting a 404 error. So I decided that URL Rewriting needed to be setup on the server to handle those type of requests.

I was able to find information on rewrites for Apache, but nothing for the IIS URL Rewrite module.

Here’s what I was able to come up with and it appears to work pretty good. (this is from web.config)

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <rewrite>
            <rules>
                <rule name="RewriteUserFriendlyURL1" stopProcessing="true">
                    <match url="^(.*)$" />
                    <conditions>
                        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                    </conditions>
                    <action type="Rewrite" url="/index.cfm/{R:1}" />
                </rule>
            </rules>
        </rewrite>
    </system.webServer>
</configuration>

and this is what should be in your Application.cfc:

component extends="org.corfield.framework" {

	variables.framework = {
		generateSES = true,
  		SESOmitIndex = true
	};

}

#coldfusion-2, #fw1, #url-rewriting

Handling Expired Sessions via AJAX & FW/1

This is a followup to my “Framework One AJAX Method (FW/1)” post (https://christierney.com/2012/07/14/framework-one-ajax-method-fw1/).

Scenario:

  1. You use the session scope to define if a user is logged in or not
  2. You use jQuery AJAX to pull JSON data from FW/1 action URL’s
  3. The user’s session has expired after x minutes of inactivity after login
  4. If the session is expired the user is directed to a login page after trying to navigate

So what happens in this scenario? Instead of the expected JSON data your AJAX call receives the HTML of a login page with a status of 200. Can’t do too much with this.

Here’s a code example that will pass the client a 403 error (Forbidden) in the header and return no content. jQuery will then redirect the user to a login screen when it sees this status code.

First here’s a simlified FW/1 Application.cfc setupRequest() method:

void function setupRequest() {

	var reqData = getHTTPRequestData();

	if( structKeyExists( reqData.headers, 'X-Requested-With' ) && reqData.headers[ 'X-Requested-With' ] == 'XMLHttpRequest' && !structKeyExists( session, 'user' ) ) {
		getpagecontext().getresponse().setstatus( 403 );
		abort;
	}
}

This code detects if the call came from an AJAX request ( getHTTPRequestData().headers.X-Requested-With = ‘XMLHttpRequest’ ) and if the session still knows about the user. If it is an AJAX request and the user is not known, then set the status code of the return page to 403 and stop processing any more code. If you try to use throw instead of abort, it will overwrite the status code to 500.

The second simple example is the jQuery piece:

$( document ).ready( function() {

	$( this ).ajaxError( function( e, jqXHR, settings, exception ) {
		if( jqXHR.status == 403 ) {
			location.href = '?logout';
			throw new Error( 'Login Required' );
		} else if( !jqXHR.statusText == 'abort' && jqXHR.getAllResponseHeaders() ) {
			alert( 'There was an error processing your request.\nPlease try again or contact customer service.\nError: ' + jqXHR.statusText );
		}
	});

});

Here we are globally looking at all AJAX requests. Since the status code 403 is in the error class it will throw an error. The .ajaxError() method picks up this error and handles it.

If the status code is detected as a 403 (which we set in our ColdFusion code) then we direct the user to a logout page (which in turn directs to a login page) and throws a JS error. The throw statement is supposed to stop all JS processing, however if you have an error handler attached to the specific AJAX call, then that will still fire. The error message will just be seen if you are viewing the JS console.

If there’s another error caught it first looks to see if the request was aborted or if the user navigated away from the page. In these two cases I don’t want to display an error. If anything else is caught, I display a generic message.

#ajax, #coldfusion-2, #fw1, #jquery, #session

FW/1 and Service Beans in ColdSpring

Recently I started switching from a Model-Glue implementation with ColdSpring to FW/1 (Framework One) with ColdSpring on a project of mine.

An example service bean definition looks like this:

<bean id="geographic" class="geographicService" />

With the new FW/1 code, I tried calling a method in this service by using:

variables.fw.service ( 'geographic.getStatesByCountry', 'states' );

But ended up with this error:

Service ‘geographic.getStatesByCountry’ does not exist. To have the execution of this service be conditional based upon its existence, pass in a third parameter of ‘false’.

After hours of debugging, my team member finally found a solution; change the bean id from geographic to geographicService. Apparently FW/1 automatically appends “Service” to the bean ID it references so that it can cache services and controllers that way. This appears to be lacking in the FW/1 documentation, or at least clearly.

So the fix is:

<bean id="geographicService" class="geographicService" />

#beans, #coldfusion-2, #coldspring, #framework, #fw1