web.config MS Access query - coldfusion

I want to do automated rewrites for my product pages in web.config.
So something like this "itemdetail.cfm?ProductID=4399" becomes "products/Ipad_3". I got this to work
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite for Products" stopProcessing="true">
<match url="products/(.+)" />
<action type="Rewrite" url="itemdetail.cfm?ProductID={Products:{R:1}}" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="Products">
<add key="Ipad_3" value="4399" />
</rewriteMap>
</rewriteMaps>
</rewrite>
</system.webServer>
</configuration>
How can I modify code in web.config to have it get "title" from MS Access database using "ProductID"? If it was coldfusion the query would be something like this
<cfquery name="GetData" datasource="myaccessdns">
SELECT Title
FROM Products
WHERE ProductID = #ProductID#
</cfquery>

Yup so as I mentioned you've got the right idea, you just need ColdFusion to generate the rewriteMap in the web.config periodically (or tie it to re-generate everytime the product title is changed or a new product is added/deleted)
generateRewriteMap.cfm
<cfquery name="AllProducts" datasource="#request.dsn#">
select ProductID, URLTitle
from Products
</cfquery>
<cfsavecontent variable="WebConfigFileData"><?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Rewrite for Products" stopProcessing="true">
<match url="products/(.+)" />
<action type="Rewrite" url="itemdetail.cfm?ProductID={Products:{R:1}}" />
</rule>
</rules>
<rewriteMaps>
<rewriteMap name="Products">
<cfoutput query="allProducts"><add key="#URLTitle#" value="#ProductID#" />
</cfoutput>
</rewriteMap>
</rewriteMaps>
</rewrite>
</system.webServer>
</configuration></cfsavecontent>
<!--- Backup the Original Web.Config --->
<cffile
action = "copy"
source = "c:/inetpub/wwwroot/mysite/web.config"
destination = "c:/inetpub/wwwroot/mysite/web.config.#getTickCount()#">
<cffile
action = "write"
file = "c:/inetpub/wwwroot/mysite/web.config"
output = "#WebConfigFileData#">
The other way I do it is convert /products.index.cfm to search for title after /products/This_Products_Title parse out everything past /products/ and then do a database search for the title of the product and pull up the appropriate page. Anything not found, returns the user to the homepage. This does require that you change all your links in your application to use the FriendlyURLTitle.

I think you want to use urlMappings.
You can use it to map a request for /products/Ipad_3 to /itemdetail.cfm?ProductID=4399 (which could even originate from a rewritten request using the code that you posted).
This is a decent guide to urlMappings: A Look at ASP.NET 2.0's URL Mapping
(Note: you can't use web.config to directly query a database)

Related

Setting up proxy headers in IIS for flask application

I have a flask application on windows running at http://localhost:3333. I want domain example.com to proxy to this application using IIS. I have setup IIS with below settings.
Added server variables HTTP_X_FORWARDED_HOST
Configured URL Rewrite module to redirect example.com to localhost:3333
There is a route in flask which I use to generate URL for forgot password like this url_for('/password_reset',_external=True).
When I access the page via example.com, all works fine where I have redirect() used. But wherever I have url_for(), the URL looks like http://localhost:3333/password_reset instead of http://example.com/password_reset. How do I make url_for() to use the external domain name properly.
Edit 1:
Current web.config
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<httpRedirect enabled="false" destination="http://localhost:3333" />
<rewrite>
<rules>
<rule name="ReverseProxyInboundRule1" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://localhost:3333/{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule1" preCondition="ResponseIsHtml1">
<match filterByTags="A, Form, Img" pattern="^http(s)?://localhost:3333/(.*)" />
<action type="Rewrite" value="http{R:1}://example.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<httpProtocol>
<customHeaders>
<add name="Host" value="{HOST}" />
</customHeaders>
</httpProtocol>
</system.webServer>
<system.web>
<httpRuntime requestPathInvalidCharacters="" requestValidationMode="2.0" />
<pages validateRequest="false" />
<identity impersonate="false" />
</system.web>
</configuration>
Edit 2:
Solution: I executed this to preserver headers and now the original host is preserved when using url_for().
"C:\Windows\System32\inetsrv\appcmd.exe" set config -section:system.webServer/proxy /preserveHostHeader:"True" /commit:apphost
you could use iis reverse proxy module for that you need to install arr:
https://www.iis.net/downloads/microsoft/application-request-routing
https://learn.microsoft.com/en-us/iis/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing
below is sample rule:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="ReverseProxyInboundRule2" enabled="false" stopProcessing="true">
<match url="(.*)" />
<action type="Rewrite" url="http://127.0.0.1:5000/{R:1}" />
</rule>
</rules>
<outboundRules>
<rule name="ReverseProxyOutboundRule2" preCondition="ResponseIsHtml1" enabled="false">
<match filterByTags="A, Form, Img" pattern="^http(s)?://127.0.0.1:5000/(.*)" />
<action type="Rewrite" value="http{R:1}://example.com/{R:2}" />
</rule>
<preConditions>
<preCondition name="ResponseIsHtml1">
<add input="{RESPONSE_CONTENT_TYPE}" pattern="^text/html" />
</preCondition>
</preConditions>
</outboundRules>
</rewrite>
<urlCompression doDynamicCompression="false" />
</system.webServer>
</configuration>
Solution that worked, as per edit.
I executed this to preserver headers and now the original host is preserved when using url_for().
"C:\Windows\System32\inetsrv\appcmd.exe" set config -section:system.webServer/proxy /preserv

Update a URL Query string in IIS URL Rewrite in IIS

I want to rewrite my URL Querystring in IIS i.e to update my ip=0
so I tried to regex like this
Actual URL
http://test.com/track/?ip=1&_=12345
Expected result
http://api.com/track/?ip=0&_=12345
MY Regex
http://test.com/([_0-9a-z-]+)/([?_0-9a-z]+)=([0-9]+)(.*)
http://api.com/{R:1}/{R:2}=0{R:4}
Can you please help me?
For the different web site, Redirect is a preferable way to Url Rewrite. Otherwise, Rewrite is applicable to the same web site.
https://blogs.iis.net/owscott/url-rewrite-vs-redirect-what-s-the-difference
We need to match the query string, and then we can assign the fragment of the query string to the new action.
ip=([0-9]+)&_=([0-9]+)
Please refer to the below screenshot.
WebConfig.
<rewrite>
<rules>
<rule name="MyRule" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{QUERY_STRING}" pattern="ip=([0-9]+)&_=([0-9]+)" />
</conditions>
<action type="Redirect" url="http://localhost/track?ip=0&_={C:2}" appendQueryString="false" />
</rule>
</rules>
</rewrite>
Here is a related discussion.
https://forums.iis.net/t/1238891.aspx?Url+Rewrite+with+multiple+querystring+

URL Rewrite same host different port in IIS 8.5

I have a server with three websites:
Default website, port 80 (no content)
Website A, port 81
Website B, port 82
I would like to use URL Rewrite to access Website A and Website B like:
http://myserver/A
http://myserver/B
instead of
http://myserver:81
http://myserver:82
I have installed the URL Rewrite and Application Request Routing modules and enabled the proxy for ARR.
On the default website I created two rewrite rules using the regex pattern /A/(.*) and /B/(.*):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WebsiteA" stopProcessing="true">
<match url="/A/(.*)" />
<action type="Rewrite" url="http://localhost:81/{R:1}" />
</rule>
<rule name="WebsiteB" stopProcessing="true">
<match url="/B/(.*)" />
<action type="Rewrite" url="http://localhost:82/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Using the Test pattern... functionality I could verify that {R:0} contained the entire test URL and {R:1} just the part after A/ or B/. The rewrite URL I sat to point to either port 81 or 82. I still regard regular expressions as pure magic but the test gave me what I wanted. Trying to connect to the websites through /A/ and /B/ gave me 404 errors.
Seeing that this is a very common problem with lots of questions and answers I picked one suggesting to use the regex pattern ^A(.*)$:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WebsiteA" stopProcessing="true">
<match url="^A(.*)$" />
<action type="Rewrite" url="http://localhost:81/{R:1}" />
</rule>
<rule name="WebsiteB" stopProcessing="true">
<match url="^B(.*)$" />
<action type="Rewrite" url="http://localhost:82/{R:1}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Using the test functionality my test URLs failed to match that pattern, but when I tried to access the sites using the new pattern, it worked.
Question: I am going with the later solution but is it pure luck that it works and should I perhaps do something different?
Is it normal for the test functionality to not successfully match the same URL's that works when I feed them to the server?

IIS ARR rules not working as expected in adding trailing slashes to my applications

I have a pool of applications that I want to run under a ARR server that should serve as a router for all my applications.
I have defined a set of rules that should be applied in waterfall, but something is not working the proper way.
The first rule should handle the trailing slashes, the other rules should map my applications to resolve for my internal DNS server with rewrite URL, but the problem seems to happen during the first rule.
The default behaviour is that, if I try to launch my application with http://myapp will return 404 code, if I try to run it by adding the slash (http://www.myapp/ ) everything works fine. So basically my rule should check for URL patterns without the slash: if the resource is a directory it should add the slash at the end of the Url.
So the pattern to catch the url is the following regular expression:
.*[^/]$
This should catch url without / at the end and I successfully tested it.
For every url that matches the regexp, I should check if it's a directory, and in the case I should set the trailing slash, so:
{REQUEST_FILE} -> Is a directory
But this doesn't work. I also tried to add the following rule with no success:
{REQUEST_FILE} -> Is not a file
The rule to apply is the following:
Redirect to (rewrite leads to same behaviour, too):
{R:O}/
It seems not to add the / to my urls and I don't know how to check which steps fail to succeed. The next rules basically follow this pattern:
mywebapp/* redirect to www.mydnsappaddress/{R:1}
EDIT: I add the web.config sample to show you the textual version of the rules.
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<clear />
<rule name="Trailing Slash" enabled="false" stopProcessing="true">
<match url=".*[^/]$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsFile" />
</conditions>
<action type="Redirect" url="{R:0}/" />
</rule>
<rule name="app1" enabled="false" patternSyntax="Wildcard">
<match url="sites/doc/*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="http://mypersonaldnsaddress/{R:0}" />
</rule>
<rule name="ASTCO portale NWS" enabled="true" patternSyntax="Wildcard">
<match url="portale/*" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false" />
<action type="Rewrite" url="http://mypersonaldnsaddress/{R:0/{R:0}" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
I have to ask the obvious: does your example deliberately have enabled set to false?
I was able to make this work exactly as you desire: if the directory exists, add a slash at the end, if it doesn't, don't.
<rule name="Trailing Slash" enabled="true" stopProcessing="true">
<match url=".*[^/]$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" />
</conditions>
<action type="Redirect" url="{R:0}/" />
</rule>

ColdFusion with IIS URL Rewrite - Page never finishes loading

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;)?nameid=([^=&]+)$" />
<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}&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
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=([^=&]+)', '/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).
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}&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;)?nameid=([^=&]+)$" />
<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>