Railo Tuckey UrlRewrite Application - Part 2

Continuation of http://www.cfjoe.com/index.cfm/2011/4/26/Railo-Tuckey-UrlRewrite-Application--Part-1

We'll take things a bit further here by turning our previous effort into a real CFML application with form submission.

This application:

  1. reads and presents the current urlrewrite.xml
  2. queries the "redirect" table
  3. outputs (dumps) the new urlrewrite.xml without overwriting the existing
  4. gives the user the option of writing the new urlrewrite.xml for either production or staging
Selecting one or the other then:
  1. Reads the current urlrewrite.xml
  2. Writes a backup of the current urlrewrite.xml
  3. Queries the database for desired 301 redirects
    1. Creates xml
    2. With rules
  4. Looping and outputting 301 query
  5. writes the new urlrewrite.xml
  6. reads it again and dumps for our viewing pleasure.

As we do not want to restart Railo each time we update urlrewrite.xml, we take advantage of the confReloadCheckInterval parameter in web.xml. See this blog entry for more info.

Why not format the xml using the XmlFormat() tag? I did try this and it took too long to parse and render. It was much quicker, and quite frankly, easier to read the string text output, using the ToString(xml) tag.

Here's the full code:

view plain print about
1<!--- ulrewritexml.cfm --->
2<!--- This app creates the xml file used for assigned 301 redirects --->
3<!--- writes urlrewrite.xml used by Tuckey rewrite filter in Tomcat --->
4
5<cfset variables.datasourcename="MyDatabase" >
6<!--- FORM PROCESSING --->
7
8<!--- we are updating 2 sites, staging and production --->
9<cfif StructKeyExists(form,"whichserver")>
10    <cfif form.whichserver EQ "staging">
11        <cfset variables.xmlfilepath="/opt/railo/tomcat/webapps/ROOT/staging.cfjoe.com/WEB-INF/urlrewrite.xml">
12        <!--- turn the rules off for staging --->
13        <cfset variables.ruleenable="false">
14    <cfelseif form.whichserver EQ "production">
15        <cfset variables.xmlfilepath="/opt/railo/tomcat/webapps/ROOT/www.cfjoe.com/WEB-INF/urlrewrite.xml">
16        <!--- turn on the rules for production - security! --->
17        <cfset variables.ruleenable="true">
18    </cfif>
19    
20<!--- read the current urlrewrite.xml --->
21<cffile action="read"
22        file="#xmlfilepath#"
23        variable="urlrewritexml">

24        
25<!--- make the back up and save --->
26<cffile action="write"
27        file="#xmlfilepath#.#DateFormat(Now(),"yyyymmdd")#-#TimeFormat(Now(),"HHmm")#"
28        fixnewline="yes"
29        output="#urlrewritexml#">

30
31<!--- What? How do we do this? confReloadCheckInterval param in web.xml. No Railo restart required! --->        
32<p>Your changes have been completed and will take 60 seconds to take affect on the web server. You may compare the old and new XML document objects below:</p>
33<p>The old urlrewrite.xml</p>        
34<cfdump var="#ToString(urlrewritexml)#">
35
36<!--- make the new xml from database --->
37<cfquery name="q301" datasource="#datasourcename#">
38 SELECT    RedirectID, OldPath, NewPath
39     FROM        redirect
40</cfquery>
41
42<cfxml variable="urlrewrite2xml">
43<?xml version="1.0" encoding="utf-8"?>
44<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
45 "http://tuckey.org/res/dtds/urlrewrite3.2.dtd">

46
47<!--
48
49 Configuration file for UrlRewriteFilter
50 http://tuckey.org/urlrewrite/
51
52-->

53<urlrewrite>
54
55 <rule>
56 <note>
57 The rule means that requests to /test/status/ will be redirected to /rewrite-status
58 the url will be rewritten.
59 </note>
60 <from>/test/status/</from>
61 <to type="redirect">%{context-path}/rewrite-status</to>
62 </rule>
63    
64 <!-- disable Railo Admin -->
65 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
66 <name>Disable Railo</name>
67 <from>^/railo-context/admin/(.*)$</from>
68 <to>null</to>
69 <set type="status">403</set>
70 </rule>
71    
72 <!-- disable Mura Admin -->
73 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
74 <name>Disable Mura</name>
75 <from>^/admin/(.*)$</from>
76 <to>null</to>
77 <set type="status">403</set>
78 </rule>
79    
80 <!-- disable WebAdmin directory -->
81 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
82 <name>Disable WebAdmin</name>
83 <from>^/WebAdmin/(.*)$</from>
84 <to>null</to>
85 <set type="status">403</set>
86 </rule>
87
88 <!-- 301 redirects from urlrewrite app -->
89    <cfoutput query="q301">
90 <rule>
91 <from>#OldPath#</from>
92 <to type="permanent-redirect">#NewPath#</to>
93 </rule>
94    </cfoutput>
95
96 <outbound-rule>
97 <note>
98 The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url)
99 the url /rewrite-status will be rewritten to /test/status/.
100
101 The above rule and this outbound-rule means that end users should never see the
102 url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks
103 in your pages.
104 </note>
105 <from>/rewrite-status</from>
106 <to>/test/status/</to>
107 </outbound-rule>
108
109</urlrewrite>    
110</cfxml>
111<cfset newurlrewritexml = ToString(urlrewrite2xml)>
112
113<!--- write the new urlrewrite.xml --->
114<cffile action="write"
115        file="#xmlfilepath#"
116        fixnewline="yes"
117        output="#newurlrewritexml#">

118
119<!--- read the new one --->        
120<cffile action="read"
121        file="#xmlfilepath#"
122        variable="viewurlrewritexml">

123<p>The new urlrewrite.xml</p>        
124<cfdump var="#ToString(viewurlrewritexml)#">
125
126<!--- SHOW FORM --->
127<cfelse>
128<p>This is the current urlrewrite.xml. The publish button is at the bottom.</p>
129
130<!--- read the current urlrewrite.xml --->
131<cffile action="read"
132        file="/opt/railo/tomcat/webapps/ROOT/staging.cfjoe.com/WEB-INF/urlrewrite.xml"
133        variable="urlrewritexml">

134        
135<cfdump var="#ToString(urlrewritexml)#">
136
137<!--- make the new xml from database --->
138<cfquery name="q301" datasource="#datasourcename#">
139 SELECT    RedirectID, OldPath, NewPath
140     FROM        redirect
141</cfquery>
142
143<cfxml variable="urlrewrite2xml">
144<?xml version="1.0" encoding="utf-8"?>
145<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
146 "http://tuckey.org/res/dtds/urlrewrite3.2.dtd">

147
148<!--
149
150 Configuration file for UrlRewriteFilter
151 http://tuckey.org/urlrewrite/
152
153-->

154<urlrewrite>
155
156 <rule>
157 <note>
158 The rule means that requests to /test/status/ will be redirected to /rewrite-status
159 the url will be rewritten.
160 </note>
161 <from>/test/status/</from>
162 <to type="redirect">%{context-path}/rewrite-status</to>
163 </rule>
164    
165 <!-- disable Railo Admin -->
166 <rule enabled="false">
167 <name>Disable Railo</name>
168 <from>^/railo-context/admin/(.*)$</from>
169 <to>null</to>
170 <set type="status">403</set>
171 </rule>
172    
173 <!-- disable Mura Admin -->
174 <rule enabled="false">
175 <name>Disable Mura</name>
176 <from>^/admin/(.*)$</from>
177 <to>null</to>
178 <set type="status">403</set>
179 </rule>
180    
181 <!-- disable WebAdmin directory -->
182 <rule enabled="false">
183 <name>Disable WebAdmin</name>
184 <from>^/WebAdmin/(.*)$</from>
185 <to>null</to>
186 <set type="status">403</set>
187 </rule>
188    
189    <!-- 301 redirects from urlrewrite app -->
190    <cfoutput query="q301">
191 <rule>
192 <from>#OldPath#</from>
193 <to type="permanent-redirect">#NewPath#</to>
194 </rule>
195    </cfoutput>
196
197 <outbound-rule>
198 <note>
199 The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url)
200 the url /rewrite-status will be rewritten to /test/status/.
201
202 The above rule and this outbound-rule means that end users should never see the
203 url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks
204 in your pages.
205 </note>
206 <from>/rewrite-status</from>
207 <to>/test/status/</to>
208 </outbound-rule>
209
210</urlrewrite>    
211</cfxml>
212<cfset newurlrewritexml = ToString(urlrewrite2xml)>
213
214<p>This would be the new urlrewrite.xml</p>        
215<cfdump var="#ToString(newurlrewritexml)#">
216
217<p>
218<form name="urlrewritexml-staging" action="urlrewritexml.cfm" method="post">
219    <input type="hidden" name="whichserver" value="staging">
220    <input type="submit" name="submit" value="Publish to Staging">
221</form>
222</p>
223
224<p>
225<form name="urlrewritexml-production" action="urlrewritexml.cfm" method="post">
226    <input type="hidden" name="whichserver" value="production">
227    <input type="submit" name="submit" value="Publish to Production">
228</form>
229</p>
230
231
232</cfif>

Railo Tuckey UrlRewrite Application - Part 1

Railo, Tomcat, Tuckey URL Rewrite filter and 301 redirects read from a database using ColdFusion or CFML.

Instead of constantly rewriting the urlrewrite.xml file with vi or nano directly on the server, we built a small ColdFusion/Railo/CFML application to easily edit our 301 redirects.

The admin side, which will not be shown here and is easy to duplicate, allows the user to add pages which will 301 redirect. They simply enter the old URL and the new URL. The table, titled redirect, has 3 columns, RedirectID, OldPath, NewPath. For example, the user wishes /my/old/page.cfm to go to my/new/directory/page.cfm with a 301 status code, and thus, would enter

What this application does:

  1. Reads the current urlrewrite.xml using cffile
  2. Writes a backup of the current urlrewrite.xml with cffile
  3. Queries the database for desired 301 redirects
    1. Creates xml
    2. With rules
  4. Looping and outputting 301 query
  5. writes the new urlrewrite.xml
  6. reads it again and dumps for our viewing pleasure.

We take advantage of the rules filter which turns on and off access to private directories like Railo and Mura admin per this blog entry.

Here's the code:

view plain print about
1<!--- ulrewritexml.cfm --->
2<!--- This app creates the xml file used for assigned 301 redirects --->
3<!--- writes urlrewrite.xml used by Tuckey rewrite filter in Tomcat --->
4
5<cfset variables.datasourcename="MyDatabase" >
6
7<!--- set file path of urlrewrite.xml --->
8<cfset variables.xmlfilepath="/opt/railo/tomcat/webapps/ROOT/cfjoe.com/WEB-INF/urlrewrite.xml">
9
10<!--- set on/off for rules - see the xml for rules --->
11<!--- we use this to disable public access to private directories --->
12<cfset variables.ruleenable="true">
13
14    
15<!--- read the current urlrewrite.xml --->
16<cffile action="read"
17        file="#xmlfilepath#"
18        variable="urlrewritexml">

19        
20<!--- make the back up and save --->
21<cffile action="write"
22        file="#xmlfilepath#.#DateFormat(Now(),"yyyymmdd")#-#TimeFormat(Now(),"HHmm")#"
23        fixnewline="yes"
24        output="#urlrewritexml#">

25        
26<!--- make the new xml from database --->
27<cfquery name="q301" datasource="#datasourcename#">
28 SELECT    RedirectID, OldPath, NewPath
29     FROM        redirect
30</cfquery>
31
32<cfxml variable="urlrewrite2xml">
33<?xml version="1.0" encoding="utf-8"?>
34<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
35 "http://tuckey.org/res/dtds/urlrewrite3.2.dtd">

36
37<!--
38
39 Configuration file for UrlRewriteFilter
40 http://tuckey.org/urlrewrite/
41
42-->

43<urlrewrite>
44
45 <rule>
46 <note>
47 The rule means that requests to /test/status/ will be redirected to /rewrite-status
48 the url will be rewritten.
49 </note>
50 <from>/test/status/</from>
51 <to type="redirect">%{context-path}/rewrite-status</to>
52 </rule>
53    
54    <!--- here are the rules! --->
55 <!-- disable Railo Admin -->
56 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
57 <name>Disable Railo</name>
58 <from>^/railo-context/admin/(.*)$</from>
59 <to>null</to>
60 <set type="status">403</set>
61 </rule>
62    
63 <!-- disable Mura Admin -->
64 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
65 <name>Disable Mura</name>
66 <from>^/admin/(.*)$</from>
67 <to>null</to>
68 <set type="status">403</set>
69 </rule>
70    
71 <!-- disable WebAdmin directory -->
72 <rule enabled="<cfoutput>#ruleenable#</cfoutput>">
73 <name>Disable WebAdmin</name>
74 <from>^/WebAdmin/(.*)$</from>
75 <to>null</to>
76 <set type="status">403</set>
77 </rule>
78
79 <!-- 301 redirects from urlrewrite app -->
80    <cfoutput query="q301">
81 <rule>
82 <from>#OldPath#</from>
83 <to type="permanent-redirect">#NewPath#</to>
84 </rule>
85    </cfoutput>
86
87 <outbound-rule>
88 <note>
89 The outbound-rule specifies that when response.encodeURL is called (if you are using JSTL c:url)
90 the url /rewrite-status will be rewritten to /test/status/.
91
92 The above rule and this outbound-rule means that end users should never see the
93 url /rewrite-status only /test/status/ both in thier location bar and in hyperlinks
94 in your pages.
95 </note>
96 <from>/rewrite-status</from>
97 <to>/test/status/</to>
98 </outbound-rule>
99
100</urlrewrite>    
101</cfxml>
102<cfset newurlrewritexml = ToString(urlrewrite2xml)>
103
104<!--- write the new urlrewrite.xml --->
105<cffile action="write"
106        file="#xmlfilepath#"
107        fixnewline="yes"
108        output="#newurlrewritexml#">

109
110<!--- read the new one --->        
111<cffile action="read"
112        file="#xmlfilepath#"
113        variable="viewurlrewritexml">

114
115<!--- lets look at it --->
116<p>The new urlrewrite.xml</p>        
117<cfdump var="#ToString(viewurlrewritexml)#">

Tuckey urlrewrite 301 redirects

Setting the <set> attribute with type=status to 301 as many examples show is NOT the right way to set your HTTP Headers status.
This is incorrect!

view plain print about
1<rule>
2 <from>OldPath</from>
3 <to type="redirect">NewPath</to>
4 <set type="status">301</set>
5 </rule>

The type attribute for HTTP Header status is placed within the <to> element. From the Tuckey URL Rewrite Filter manual

Attribute Possible Value Explanation
type
(optional)
forward (default) Requests matching the "conditions" for this "rule", and the URL in the "from" element will be internally forwarded to the URL specified in the "to" element. Note: In this case the "to" URL must be in the same context as UrlRewriteFilter. This is the same as doing:
RequestDispatcher rq = request.getRequestDispatcher([to value]);
rq.forward(request, response);
passthrough Identical to "forward".
redirect Requests matching the "conditions" and the "from" for this rule will be HTTP redirected. This is the same a doing:
HttpServletResponse.sendRedirect([to value]))
permanent-redirect The same as doing:
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.setHeader("Location", [to value]);
(note, SC_MOVED_TEMPORARILY is HTTP status code 301)
temporary-redirect The same as doing:
response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
response.setHeader("Location", [to value]);
(note, SC_MOVED_TEMPORARILY is HTTP status code 302)
last
(optional)
false (default) The rest of the "rules" will be processed if this one succeeds.
true No more "rules" will be processed if this one is a match.
encode
(optional)
false (default if under rule) response.encodeURL([to]) will be run on the to url before performing the rewrite.
true (default if under outbound-rule) response.encodeURL([to]) will NOT be called.

This is what is should be for a 301 redirect:

view plain print about
1<rule>
2 <from>OldPath</from>
3 <to type="permanent-redirect">NewPath</to>
4 </rule>

BlogCFC was created by Raymond Camden. This blog is running version 5.9.7. Contact Blog Owner