2

I am running CF10 on IIS 7.5 with URL Rewrite module installed. All the rewrite rules work perfectly and ColdFusion is returning the correct pages. In order to get the page displayed in the browser I have to manually set the 'content-length' value in Application.cfc like this:

<cfcomponent>

  <cffunction name="onRequestEnd">

  <cfheader name="Content-Length" value="#getPageContext().getCFOutput().getBuffer().size()#" />

  </cffunction>

</cfcomponent>

Without this code the browser does not display the page. However, even though it is now displaying the page, it is not doing it correctly. The page never finishes loading fully and not all of the HTML content seems to be on the page.

I have tried to add a <cfflush /> tag after setting the 'content-length' but it makes no difference. I don't understand why this is happening but I know that it has happened to someone else who was using htaccess:http://forums.devshed.com/coldfusion-development-84/page-not-finishing -loading-coldfusion-and-htaccess-bug-575906.html

EDIT: Example Outbound/Inbound Rule Definition:

<!--- Outbound rule --->
<rule name="Rewrite Info Page" preCondition="IsHTML" enabled="false" stopProcessing="false">
<match filterByTags="A" pattern="^(.*)/info\.cfm\?subjectid=([^=&amp;]+)&amp;(?:amp;)?nameid=([^=&amp;]+)$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
</conditions>
<action type="Rewrite" value="{R:1}/info/{R:2}/{R:3}" />
</rule>

<preConditions>
<preCondition name="IsHTML">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>


<!--- Inbound rule --->
<rule name="Rewrite Info Page" enabled="true" stopProcessing="false">
<match url="^(.*)/info/([^/]+)/([^/]+)/?$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="{R:1}/info.cfm?subjectid={R:2}&amp;nameid={R:3}" appendQueryString="true" />
</rule>

The Outbound rule is looking at a URL link within an <a> tag that looks like http://mysite.com/info.cfm?subjectid=1&nameid=1 and then rewriting it to appear on my page as http://mysite.com/info/1/1.

The Inbound is looking for a link that looks like http://mysite/info/1/1 and resolving/rewriting it to the real URL which is http://mysite.com/info.cfm?subjectid=1&nameid=1

volume one
  • 6,800
  • 13
  • 67
  • 146
  • I doubt it's the rewrite module, but for the sake of troubleshooting, switch it off and hit a page via an unmolested URL. Same? Is it the same for any page? Have a look at some CF monitoring and check to see whether CF thinks it's finished processing the request, or whether it's not releasing it. Reinstall the web server connector and see if that helps. – Adam Cameron Sep 17 '13 at 06:02
  • Hi Adam, I have done this and there are no problems when the rewrite module is off. Therefore its something to do with IIS Rewrite Module. I'm now trying out helicon ape which uses apache mod_rewrite to see if I can make it work – volume one Sep 17 '13 at 12:22
  • Turns out that mod_rewrite can't change HTML content on the fly :( which means all my URLs have to be rewritten into friendly-URLs within my CF code. This will cause headaches when it comes to checking for orphaned/broken links. – volume one Sep 17 '13 at 13:44
  • Open your browser dev tools (Firebug or similar) and watch the network traffic as the page loads. Are there are any 404s or other HTTP error codes returned for any of your linked assets? Rewriting a file from `/path/file.cfm` to `/path/file/` can screw up relative path references in your code, causing CSS, images, and JavaScript to simply not work. – imthepitts Sep 17 '13 at 16:52
  • No 404 errors at all. The headers look fine as well. But the browser will continue to show a spinning icon waiting for the page to load. I noticed that not all of the HTML is outputted to the browser sometimes and Firebug comes back with slow response times when Outbound is turned on. I'm pretty sure that the Outbound link rewriting is taking too long (there are lots of links on my pages) and this causing ColdFusion to return pages erratically. This is why I have to set the content-length header manually just so that the page even shows up in the browser despite the loading issues. – volume one Sep 17 '13 at 22:27
  • ColdFusion isn't even aware any of this is happening. Inbound rewriting occurs *before* IIS hands off the request to ColdFusion and outbound link rewriting occurs *after* ColdFusion has processed the page and returned HTML to IIS. Do you have any problems when outbound is turned off? – imthepitts Sep 17 '13 at 22:32
  • No problems at all when Outbound is turned off. The Inbound rewrites work fine then, the page loads fully :) – volume one Sep 17 '13 at 22:33
  • Please edit your question to include your outbound rule definition/configuration. – imthepitts Sep 17 '13 at 22:34

2 Answers2

1

I was able to get your outbound rules to work pretty much as is on my local dev environment (although running CF9). The only trouble was getting the outbound rules wrapped in the correct XML elements.

After that, IIS told me outbound rules could not be applied to gzipped content, so I had to add <urlCompression doStaticCompression="true" doDynamicCompression="false"/> to the configuration.

With that in place, the outbound rewrite worked perfectly. I even ran it against a page that had over 20,000 links, and it handled it fine.

Here is my <rewrite> section for web.config along with the <urlCompression> bit:

    <rewrite>
        <rules>
            <rule name="Rewrite Info" enabled="true" stopProcessing="false">
                <match url="^(.*)/info/([^/]+)/([^/]+)/?$" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                    <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
                    <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
                </conditions>
                <action type="Rewrite" url="{R:1}/info.cfm?subjectid={R:2}&amp;nameid={R:3}" appendQueryString="true" />
            </rule>
        </rules>
        <outboundRules>
            <rule name="Rewrite Info Page" preCondition="IsHTML" enabled="true" stopProcessing="false">
                <match filterByTags="A" pattern="^(.*)/info\.cfm\?subjectid=([^=&amp;]+)&amp;(?:amp;)?nameid=([^=&amp;]+)$" />
                <conditions logicalGrouping="MatchAll" trackAllCaptures="false">
                </conditions>
                <action type="Rewrite" value="{R:1}/info/{R:2}/{R:3}" />
            </rule>
            <preConditions>
                <preCondition name="IsHTML">
                    <add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
                </preCondition>
            </preConditions>
        </outboundRules>
    </rewrite>
    <urlCompression doStaticCompression="true" doDynamicCompression="false"/>

I found no difference in the result when including <cfheader name="Content-Length" value="#getPageContext().getCFOutput().getBuffer().size()#" /> in onRequestEnd.

However, since you are getting the spinner and the page never seems to fully load, you might try explicitly flushing and closing the response in onRequestEnd to ensure the handoff back to IIS is complete:

<cfscript>
    var response = getPageContext().getResponse().getResponse();
    var out = response.getOutputStream();
    out.flush();
    out.close();
</cfscript>
imthepitts
  • 1,647
  • 10
  • 9
  • I edited my question again due to some errors in my example rules. There shouldnt be anything with the word 'course'. I am surprised it is working for you.... I have tried on two seperate dev machines and even a production machine and keep getting the same problems. I'll review your code now.... – volume one Sep 18 '13 at 00:06
  • @volumeone, that explains why the inbound rule wasn't working. :o) I revised my web.config code in my answer to reflect the changes. Inbound rule is working for me now. – imthepitts Sep 18 '13 at 00:11
  • Just tried it and it doesn't work for me. It must have something to do with the new Tomcat server in CF10? – volume one Sep 18 '13 at 00:24
  • Based on the architecture of app server to web server, ColdFusion would have already relinquished control back to IIS. So CF10 *shouldn't* make a difference. I suspect there is some other environmental issue at play. Perhaps other settings in your web.config. I would suggest two more things: 1) Change stopProcessing="false" to stopProcessing="true" in your outbound rule. There may be additional rules being processed that are interfering. 2) Strip down your CFM page and web.config file to their barest essentials to see if it works. Then add back in pieces one at a time to identify the culprit. – imthepitts Sep 18 '13 at 00:57
  • You are correct, the Outbound rules do work. But once the Outbound rules have rewritten the links, try clicking on a link to take you to another page which has more links on it. It breaks for me unless I put it in the content-length header manually.... and then the page never finishes loading. – volume one Sep 18 '13 at 14:41
  • Here's my test case with some instructions: https://gist.github.com/imthepitts/6610996. See if you can get this simple test case to run for both inbound and outbound rules. If you can, then slowly add in other pieces from your project to identify the culprit. – imthepitts Sep 18 '13 at 15:38
  • It works fine, but if I click on one of the links which should then take me to the info.cfm page with more rewritten links on, it fails and I get nothing displayed. So try creating a page called pre-info.cfm which has the list of links like in your test case. Then create an info.cfm page which will display the same set of links that pre-info.cfm does. Have it so that clicking on a link on pre-info.cfm takes you through to info.cfm. What happens then is that info.cfm will never display unless you set the content-length in Application.cfc. Does this happen for you as well? – volume one Sep 18 '13 at 20:38
  • That works fine in my environment, too. If this simple test case isn't working for you, I'm not sure where to go from here. – imthepitts Sep 18 '13 at 20:51
  • I've had to give up and put user-friendly URLs in the code itself. Not great in my opinion, but it does give me one advantage that I can have default documents again. When outbound rules are on, you can't have default documents. Thank you for all your help, I really do appreciate you taking the time and effort to assist me. – volume one Sep 18 '13 at 21:42
  • Well, you *could* do the same thing with `reReplace()` against the output stream in `onRequestEnd`. Won't perform as well as using IIS, but would give you everything else. – imthepitts Sep 18 '13 at 23:03
1

Since IIS URL Rewrite's outbound rules are giving you so much trouble, here is another option. Use ColdFusion to rewrite the links in onRequestEnd. This will allow you to use physical paths in your IDE, use default documents, and still get the outbound URLs sent to the browser in the desired format. I've updated my Gist with the details.

Here is a very basic approach. Turn off the outbound rewrite rule in web.config and add something like this to your onRequestEnd function in Application.cfc. (My regex is horrible, so this reReplace() pattern only partially works the way your IIS pattern did.

<cfcomponent>

    <cffunction name="onRequestEnd">
        <!--- Get the generated output --->
        <cfset var output = getPageContext().getCFOutput().getBuffer().toString()>      

        <!--- Apply outbound link rules --->
        <cfset output = reReplace(output, '/info\.cfm\?subjectid=([^=&amp;]+)', '/info/\1', 'all')>

        <!--- Clear the previous output and send the rewritten output in its place --->
        <cfcontent reset="true">
        <cfoutput>#output#</cfoutput>

    </cffunction>

</cfcomponent>

This won't perform as well as the URL Rewrite module in IIS, but it will give you everything else you are trying to achieve (once you get your regex tuned up).

imthepitts
  • 1,647
  • 10
  • 9
  • Thats very interesting. I was thinking about something along these lines, perhaps not as elegant as what you've described. Do you think doing it this way will use more server resources (mainly CPU I guess) than using IIS Rewrite Module? – volume one Sep 19 '13 at 10:42
  • @volumeone, like I said, it won't perform as well as the URL Rewrite module. URL Rewrite is much "closer to the metal" compared to ColdFusion. ColdFusion is a higher level language that must get compiled to Java, which runs on top of the JVM, which then interfaces with the OS. Also, Java is known for being relatively slower at string manipulation than other languages. Implementing outbound rewriting rules in this manner should be done carefully and load tested thoroughly to make sure you don't have any adverse impact. – imthepitts Sep 19 '13 at 15:59