[Coldbox 6.5.2] How Can I Have Coldbox Handle a URL Like "/resources/" When The Folder Already Exists?

Elixir + Coldbox is a powerful duo for developing modern web apps and introduces some convenient conventions for developers to keep things organized. One of these conventions is storing raw SCSS/JS source files in a /resources/ folder in the web root.

image

However, I’ve been having a hard time creating and using a handler with the name “resources” because it conflicts with the actual directory “/resources/”.

If you try and bring up the URL: http://127.0.0.1:58534/resources/, I would expect it to trigger the index() action within the resources handler, however because the folder /resources/ exists, the web server shows the contents of the directory. In development, it looks like this:

image

I assume the fix is to tell the web server to let Coldbox handle the request through a new URL rewrite mapping, but everything I’ve tried doesn’t seem to work. Here’s what I’ve tried so far:

  1. Start the server with --debug flag.
  2. Keep a console open via server log --follow
  3. Set up server.json to use a custom rewrites file as follows:
{
    "web":{
        "rewrites":{
            "enable":"true",
            "config":"customRewrites.xml",
            "configReloadSeconds":"30",
            "statusPath":"/tuckey-status"
        }
    },
    "app":{
        "cfengine":"adobe@2018",
        "_prior_cfengine":"lucee"
    },
    "name":"myapp"
}

I learned early on that I have to copy/paste the default rewrite rule Coldbox needs at the beginning of the customRewrites.xml file. My idea was to then follow up with an additional rule to pass through the exact URL /resources/ and pass through the request to index.cfm like this:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN" "http://tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
    <!-- Turn resources/ into /index.cfm/resources/ -->
    <rule>
        <from>^/resources$</from>
		<to type="passthrough">/index.cfm/resources</to>
    </rule>
	<rule>
		<note>Generic Front-Controller URLs</note>
		<!-- These are paths that don't exist on disk, but shouldn't get rewritten since the CF engine treats them special. -->
		<condition type="request-uri" operator="notequal">^/(flex2gateway|flashservices/gateway|messagebroker|lucee|rest|cfide|CFIDE|cfformgateway|jrunscripts|cf_scripts|mapping-tag|CFFileServlet)/.*</condition>
		<!-- This is a special URL that can be enabled with debugging -->
		<condition type="request-uri" operator="notequal">^/tuckey-status</condition>
		<!-- Used for the Adobe CF 2018 performance monitoring service -->
		<condition type="request-uri" operator="notequal">^/pms$</condition>
		<!-- Browsers like to send this request and it will get rewritten to /index.cfm/favicon.ico when it really just needs to be a 404 -->
		<condition type="request-uri" operator="notequal">^/favicon.ico</condition>
		<!-- Ignore any path to a .cfm or .cfml file in a sub directory that has a path info attached. These won't trigger as "real" directories below
		since the rewrite filter doesn't know what part is the actual file name.  Note, the ses path info servlet filter hasn't fired yet. -->
		<condition type="request-uri" operator="notequal">^/.*\.cf(m|ml)/.*</condition>
		<!-- Do not rewrite paths that point to real files or directories -->
		<condition type="request-filename" operator="notdir"/>
		<condition type="request-filename" operator="notfile"/>
		<!-- Turn localhost/foo into localhost/index.cfm/foo -->
		<from>^/(.+)$</from>
		<to type="passthrough">/index.cfm/$1</to>
	</rule>
</urlrewrite>

Unfortunately, my debug output produces this:
image

If anyone has any tips for how I need to modify customRewrites.xml, your assistance would be most appreciated!

Let me try to understand your situation a bit better here.

Usually with ColdBox Elixir you build your assets into the includes folder. I know for pretty much all our ColdBox Elixir apps, this is what we are doing. Then we serve the files out of includes. In fact, we usually delete the resources folder from the built Docker image because it’s not used after running this build step.

It seems like you might be serving files directly from the resources folder. Is that correct? If not, where are your built files being saved to?

1 Like

Sorry for the confusion. The root of the question is how to have Coldbox handle a request, when a directory with the same name already exists. In my case, the folder name is /resources, but it could be anything really (e.g. /foo). If the handler name matches a real folder that exists on the file system, the web server will bypass Coldbox.

I haven’t mastered the fancy Docker/deployment stuff so I’m still deploying via git checkouts. Therefore, my resources/ folder still exists in the web root. Hopefully, there will be a class on Docker deployments on CFCasts soon! :wink:

Easy, just remove this part of your rewrite

<condition type="request-filename" operator="notdir"/>
1 Like

Thanks Brad,
If I remove that line, wouldn’t it impact all URLs that point to directories? (e.g. mysite.com/images, mysite.com/documents). I want to set up a rule for a specific folder /resources/. Wouldn’t prepending a new <rule> be the best way to create a special exception like this?

<rule>
  <from>^/resources$</from>
  <to type="passthrough">/index.cfm/resources</to>
</rule>
... rest of default rewrites for Coldbox

Not necessarily. It depends on what you mean when you say "points to directories. The following URL is pointing to a directory

site.com/resources/

This URL is not pointing to a directory

site.com/resources/styles.css

So to be clear, do you have URLs that point explicitly to directs (NOT files inside a directory)?

But to answer your second question-- yes of course, You can create as many rules as you like and customize them how you see fit Tuckey’s XML is documented so have at it :slight_smile:

1 Like

Yes, in this example, I have the URL mysite.com/resources/ which should point to the Coldbox event resources.index. However, because the folder exists, when I type mysite.com/resources/ I get the directory listing instead.

I’ve even tried debugging with a dramatically simple config and can’t get it to rewrite. In theory, this example should redirect anyone going to /resources/ to /foo/

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN" "http://tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
    <rule>
        <from>^/resources$</from>
		<to type="permanent-redirect">/foo</to>
    </rule>
</urlrewrite>

I even checked it with the tuckey debugger:
image

Yes, obviously! That’s why told you to remove the directory check from the rule! You asked if that would affect other requests to directories and I asked if your application actually has directories that you legitimately want a directory listing of. If not, (and I assume not since that’s not a common practice in a production server) then you should have nothing to worry about.

Thanks for the clarification. Your solution of removing:
<condition type="request-filename" operator="notdir"/>
Makes sense to me so Coldbox will handle all directory URLs (with no filename). I can confirm that this change does work.

However, let’s say for example, I only want to change this behavior for a single folder, /resources (and not any subfolder beneath it like /resources/img, /resources/js), creating a new rule, is the way to go, right?

I believe that by adding the following rule does what I want it to do:

<rule>
    <from>^/resources/$</from>
    <to type="passthrough">/index.cfm/resources</to>
</rule>

The trick was to add the extra slash after resources and before $.

The above rule tells ColdBox to handle requests to:
/resources
/resources/
but it ignores everything else, like:
/resources/img/ (returns 403 or directory listing as expected)
/resources/img/flower.jpg (returns the image)

However, I like Brad’s suggestion of simply removing…
<condition type="request-filename" operator="notdir"/>
… from the default rules because it hides the directory structure of your website.

Hopefully, this thread helps anyone else in a similar predicament. Thanks, @bdw429s and @elpete for your help. :slight_smile:

Correct, that is a valid way to handle it and more surgical than changing the general purpose rule.

1 Like