framework-one / fw1

FW/1 - Framework One - is a lightweight, convention over configuration, MVC application framework for ColdFusion / CFML.
http://framework-one.github.io
Other
373 stars 141 forks source link

unhandledPaths not working inside sub folder #510

Open charlesr1971 opened 5 years ago

charlesr1971 commented 5 years ago

Environment:

  1. ACF11
  2. FW1 4.3.0
  3. Windows 10

When I use the following inside Application.cfc:

component extends = "framework.one" {

    this.name = Hash(GetBaseTemplatePath());
    this.sessionManagement = true;
    this.mappings[ '/components' ] = GetDirectoryFromPath(GetCurrentTemplatePath()) & "\components";
    variables.framework = {
        home = "blog.list",
        unhandledPaths = "/includes"
    };

}

I have also tried:

component extends = "framework.one" {

    this.name = Hash(GetBaseTemplatePath());
    this.sessionManagement = true;
    this.mappings[ '/components' ] = GetDirectoryFromPath(GetCurrentTemplatePath()) & "\components";
    variables.framework = {
        home = "blog.list",
        unhandledPaths = "/fw1/mushroom-man/includes"
    };

}

And I try and access the following template directly:

http://localhost:8500/fw1/mushroom-man/includes/test.cfm

I get the following error. Please see screenshot below:

14216164-FA34-42ED-93A7-6DE47C12F169

And here is my directory structure:

8D17D538-BFA8-4952-880A-36354DA5CB0E

My Application.cfc & framework directory are in:

/fw1/mushroom-man/

Some of my colleagues think the problem may be caused by the fact that the FW1 framework is located in a subdirectory of the webroot.

Update 04.09.19

I have added a CommandBox Installation of FW1 in a sub directory:

fw1 create app fw1TestSubdir basic C:\ColdFusion11\cfusion\wwwroot\fw1\fw1-test-subdir true

For some reason, the framework folder did not get installed, so I installed it manually:

cd C:\ColdFusion11\cfusion\wwwroot\fw1\fw1-test-subdir
install fw1

My Appilcation.cfc

component extends="framework.one" output="false" {

    this.name = Hash(GetBaseTemplatePath());
    this.applicationTimeout = createTimeSpan(0, 2, 0, 0);
    this.setClientCookies = true;
    this.sessionManagement = true;
    this.sessionTimeout = createTimeSpan(0, 0, 30, 0);

    // FW/1 settings
    variables.framework = {
        action = 'action',
        defaultSection = 'main',
        defaultItem = 'default',
        generateSES = false,
        SESOmitIndex = false,
        diEngine = "di1",
        diComponent = "framework.ioc",
        diLocations = "model, controllers",
        diConfig = { },
        reloadApplicationOnEveryRequest = true,
        unhandledPaths = "/fw1/fw1-test-subdir/includes",
        routes = [ ]
    };

    public void function setupSession() {  }

    public void function setupRequest() {  }

    public void function setupView() {  }

    public void function setupResponse() {  }

    public string function onMissingView(struct rc = {}) {
        return "Error 404 - Page not found.";
    }

}

I have then added the following directory & file:

/fw1/fw1-test-subdir/includes/test.cfm

I have then tried to access:

http://localhost:8500/fw1/fw1-test-subdir/includes/test.cfm

And I get the following message:

Error 404 - Page not found.

On further investigation, when I removed the

onMissingView

Method of the Application.cfc

I now get the original error back:

screenshot-3

sneiland commented 5 years ago

See comment on slack thread. https://cfml.slack.com/archives/C06TA3B3L/p1567550207059800

mjclemente commented 5 years ago

If the issue ends up being resolved in that Slack thread, we should be sure to include the relevant comments here, for posterity.

charlesr1971 commented 5 years ago

@mjclemente Yes. I am doing some commandBox tests today with a sub directory FW1 installation. I will post my results.

charlesr1971 commented 5 years ago

@sneiland @mjclemente Based on the CommandBox tests I did today, the details of which I have added to the original submission, and from comments made on Slack, both myself and @tonyjunkes, believe that this issue is a bug.

tonyjunkes commented 5 years ago

Just to note here, following similar steps to what @charlesr1971 documented here, I was able to reproduce the scenario. I started dissecting FW/1's process up to attempting to either ignore the request or move on to rendering a view but haven't discovered anything substantial to back up how this is occurring.

One thing I noticed is I was unable to trigger a dump/abort of the variables/framework settings within FW/1's onRequestStart method when hitting the unhandled path in the browser. It seems like it moves right to onRequest and attempts to draw a view/layout. Completely ignoring the check for an unhandled path. If I find anything more useful, I'll post back.

charlesr1971 commented 5 years ago

@tonyjunkes It seems that the unhandledPath value is formatted by framework/one.cfc, using the method:

setupFrameworkDefaults()

Into:

variables.framework.unhandledPathRegex

But never gets to the next method:

IsUnhandledRequest()

So, somewhere, between these 2 steps, an error gets thrown. Looking at the error trace, it seems like FW1 attempts to build a new view path, completely ignoring the value of the:

variables.framework.unhandledPaths

It maybe that the view path calculation is made before:

IsUnhandledRequest()

Is executed, and then depending on the Boolean that is returned, from the above method, the view path is then either deleted or followed. The fact that the FW1 installation is in a sub directory of the webroot, maybe creating a path that is not recognised by certain regex rules, that are responsible for assessing whether a path is a valid view directory or not. This maybe the case, if the regex only expects the path length to have a single '/' delimiter, which would be the case, if the FW1 installation was located in the webroot. Or, if the regex only expects a non standard view path value, similar to one that is explicitly declared by:

variables.framework.viewsFolder

Tomorrow, I may try and explicitly set the:

variables.framework.viewsFolder

And, see, if this helps to guide the regex path parsing engine. This may provide a temporary workaround.

charlesr1971 commented 5 years ago

Changing the:

variables.framework.viewsFolder

Did not make any difference.

I still get the error.

charlesr1971 commented 5 years ago

In the end, I had to place an Application.cfc in the includes directory, which is a real pain in the backside.

I then had to create an include of all the content of my parent Application.cfc's setupRequest function and then I added this include to both the parent and child Application.cfc request method. This is very janky, so I really hope someone might be able to fix this bug.

Thank you for everyone's help on this issue.

sneiland commented 4 years ago

I was able to spend some time this week attempting to replicate this issue using the folder structures described here, however I have not been able to replicate the issue when supplying the expected folder paths.

Please review the test case at "https://github.com/framework-one/fw1/tree/issue/510/tests/issue510" and let me know what additional steps are needed to recreate the issue.

Note that the directory "issue510" is the webroot for the supplied command box files to run this for adobe cf 11.

box start adobe@11.0.10 http://localhost:18145/fw1/folder-with-dashes/includes/test.cfm

tonyjunkes commented 3 years ago

I came back to this and was able to recreate the issue again. This time I think I narrowed it down.

At the start of the event chain, setupApplicationWrapper() is called and creates/sets the parent bean factory. In a scenario where FW/1 is in a subdirectory, the process tries to create the bean factory object using a path that also includes the unhandled path being accessed. This results in an object creation error stating framework.ioc cannot be found. When onError() fires, onRequestStart() fails, skipping the unhandled path check logic, but continues to onRequest(), where it will look for an FW/1 view as if it was still evaluating usual framework conventions. This results in the resulting error that we see.

It looks like a viable solution is to add a check in setupApplicationWrapper() using isUnhandledRequest() to verify if the cgiScriptPath in the request matches an unhandled path and exit the method call before setting a bean factory.

I have this as a working fix locally, and I am just verifying if I can put together a test case to help get some coverage on this issue. All existing tests pass which is a good sign. When I get a chance I will commit to my repo and file a PR for review.

Cheers.

sneiland commented 3 years ago

Thanks for looking into that further tony, I'll keep an eye out for that PR.

tonyjunkes commented 3 years ago

@sneiland,

I have a PR ready to be submitted for review but could not for the life of me get a test case to correctly reproduce the issue. Not sure if it's me, or it just can't easily be triggered programmatically without being more of an "integration" approach. I've personally found replicating life cycle events to be tricky. I can however reproduce with an actual application structure much like how you have set up in branch issue/510.

So I can either commit the code as is with existing tests passing or, also commit a small condensed app structure in the tests directory that would represent how the issue could occur. My only gripe with including the scenario structure is it wouldn't be automated obviously.

How would you like me to proceed?

Cheers!

sneiland commented 3 years ago

Can you commit the condensed app to the test directory please.