5

We have recently gone through the process of upgrading from CF11 to CF2023. On our development servers, everything seemed work as expected. However, after installing on our production server, we have found a weird issue.

The fileRead command in a cfc file, seems to read the file, but then a 500 error is thrown after the cfc has finished processing. The issue does not happen with any other command in any other cfc (that we have found yet). I can reproduce this issue on our production serve; but using the same test page in development (or test) the code works fine.

Our immediate workaround is to use cffile action="read". This seems to work fine in development and production.

Sample test code that works in development but not in production (the file is read, contents dumped per the code, but then the 500 error is overlayed on the file dump) - fileReadTest.cfc:

component {

    struct function getRules() {

        try {

        var _rules = fileRead('[path]/configuration.json');
            _rules = deserializeJSON(_rules);

        return _rules;

        } catch( any e) {
            cfdump( var = e);
        }
    }

    remote string function test() {
        try {

            var _r = getRules()
            cfdump(var = _r);

            return 'test'

         } catch( any e) {
            cfdump( var = e);
        }
    }

}

These test is being called (for testing purposes) via the url with method as a parameter:

https://ourdoman.edu/fileReadTest.cfc?method=test

I do have access to the coldfusion administrator pages. I have compared prod to dev via the Settings Summary page and everything seems in line. I do not have access to IIS, but I am assured that those settings match from server to server.

One thing to note is that our dev server cannot be accessed from outside our network. In other words, you have to be on campus to use dev.

In looking at the coldfusion-error.log, I can see a SEVERE: Servlet.service() for servlet [CFCServlet] in context with path [] threw exception which seems to coincide with when the 500 error is generated. Looking up that error seems to lead to an IIS issue but I don't see anything definitive that I could point our network administrator to review.

Any insight would be super helpful. While we can use cffile as the workaround, my concern is that this is a sign of a bigger configuration issue.

Thanks

Edit:

Slimmed down version of the code to reproduce the error:

component {
    string function getRules() {
        var _rules = fileRead('c:/applications/test/test.txt');
        
        return _rules;
    }

    remote string function test() {
        var _r = getRules();
        return _r;                
    }
}

test.txt = This is a test.

Results: File is read, data is cfdumped, and then the 500 error Results: File is read, data is cfdumped, and then the 500 error1

Update: As a test, I tried using fileRead to read a fileObject as returned by fileOpen. For example:

 var x = fileOpen('[path]/test.txt')
 var y = fileRead(x, 16);
         fileClose(x);

The result is the same. The file is read and outputted (see sample code above), but then the 500 error is displayed. If I take out the fileRead, the fileOpen and fileClose seem to work without issue.

Also, it was suggested to me that I look at the application.cfc onRequestStart / onRequestEnd. I can verify that those are executing normally - as a test, I had them send an email per start and end. Also, the onError in the application.cfc will send an email as well if an error where to occur.

Testing Update

In my test cfc, I created a loop to iterate over the function that calls the fileRead. Each iteration calls the fileRead successfully as indicated by the data being cfdumped. Once the iteration is completed, the 500 error is generated.

Response

I thought it might helpful to see what the console response looks like. For example if the file is "this is a test", the response looks like the following. First file content and then the 500 Error is appended to the response.

<wddxPacket version='1.0'>
    <header/>
    <data>
        <string>
            this is a test<char code='0d'/>
            <char code='0a'/>
        </string>
    </data>
</wddxPacket>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>500</title>
        <style>
            body { 
    ... 

A Clue?

An important clue (?): If the .cfc that does the fileRead is called from a .cfm, using cfhttp,createObject,invoke, it works with no error. But if called via [URL]/test.cfc?method=getData or (as the app was initially doing) via $http (AngularJS), the error is generated. Both of those methods are using the same URL. It also fails if called from another cfc.

Another tidbit FileWrite behaves the same way as FileRead. When called from a .cfc, it writes the file, but then throws the 500 Error.

Stack Trace

Jul 11, 2023 1:08:07 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [CFCServlet] in context with path [] threw exception
java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.get(Optional.java:143)
    at coldfusion.monitor.beans.RequestData.isGraphQlService(RequestData.java:795)
    at coldfusion.monitor.beans.RequestData.updateFunctionMetrics(RequestData.java:618)
    at coldfusion.monitor.beans.RequestData.updateTagData(RequestData.java:459)
    at coldfusion.monitor.beans.RequestData.updateData(RequestData.java:223)
    at coldfusion.monitor.event.RequestMonitorEventProcessor.onRequestEnd(RequestMonitorEventProcessor.java:419)
    at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:82)
    at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:47)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:373)
    at org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:459)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
    at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:833)
snackboy
  • 624
  • 3
  • 12
  • 2
    Your `cffile` example doesn't return the deserialized `_rules`. That probably isn't the issue though. Try removing `cfdump` in the catch to avoid running into a timeout. Can you tell us something about what kind of data the read file contains, like content size and nesting levels? – Alex Jul 09 '23 at 22:06
  • Thanks @Alex. I've simplified the test code to remove the json and replace it with a text file. The 500 error is still generated. What is bizarre is that the file IS being read and the results are dumped (I try to upload an image). But then the 500 error displayed on top of the dump. Our DEV server, which only faces internally, works fine. – snackboy Jul 10 '23 at 13:58
  • 2
    This is the most clear and detailed question I've seen in quite some time. Are all the files located in the same directory? Could the 500 error be related to something post-read? – Adrian J. Moreno Jul 10 '23 at 15:23
  • The files are on the same server. I've tested with different files in different paths yielding the same result. I do think it is something related to post-read specifically with the fileRead function. While our system isn't overly active right now because students aren't on campus, we haven't seen any other 500 error issues. – snackboy Jul 10 '23 at 15:58
  • @snackboy Have you tried running the file read by itself? Just some isolated test without anything before or after? – Adrian J. Moreno Jul 10 '23 at 20:05
  • The initial filedRead was as the beginning of a cfc because it was loading a json configuration file, and that's when we discovered the error. When I tested the fileRead in a .cfm it worked. But even in a stripped down CFC, it generates the error. In looking at the [Chrome] Console, the Status Code is 200 (for any instance of the test). – snackboy Jul 10 '23 at 20:12
  • The error says "The image you are trying to access cannot be displayed", which sounds like the image file itself is invalid or something similar. Do you get the error if you abort immediately after the read? More generally, what line of code is actually crashing? Is the "can't be displayed" message the actual crash? Maybe make a copy of the file, wrapped in try/catch, see what you can figure out from there. – enigment Jul 10 '23 at 20:15
  • The error says the "page" (though I wish it said image). I've put cftry / cfcatch on the component functions to no avail. I've even put cftry / cfcatch on the onRequestStart / onRequestEnd in the application.cfc and confirmed via emails that they are starting and ending without issue. Since the same code is working in our development environment, I don't think it's a code issue per se, but something on the production server or some type of setting. – snackboy Jul 10 '23 at 20:29
  • Is the dump in the screenshot reflecting *all* of the data in the file you are loading? Is any data missing (particularly any empty or null values)? – Carl Von Stetten Jul 10 '23 at 21:00
  • Yes, it's all the data. I've tested with even a simpler text file, and all the data is loaded, but the 500 error persists. – snackboy Jul 10 '23 at 21:05
  • 4
    This may sound obvious, but going back to Adrian's suggestion about running the file read by itself, can you confirm if you have put those few lines of code (only the fileread-related stuff) in a cfm of its own, in a folder of its own, with an empty application.cfm/cfc. Does it happen then? If not, what if then put in a cfc of its own (no implements or extends, no other methods) and have a cfm call it? Also, I'd ignore that one error from the log and look in all other CF logs at the same time (don't trust the file date modified time). I could say more, let's see where this gets you. – charlie arehart Jul 10 '23 at 22:23
  • Okay. I've created a .cfm which calls the .cfc with the `fileRead` via `createObject` and it worked with no error. Then I created another cfc to chain the cfc calls: cfm > cfc (to make the call) > cfc (to read the file) and no errors. I even tried `cfhttp` in the cfm and that worked too. However, if I put the cfhttp url directly in the browser, 500 error. So it would seem that calling the cfc from a .cfm does not yield an error. And, if the cfc is called from $http (as in AngularJS), the data is returned and 500 error (which is where the error was initially discovered). – snackboy Jul 10 '23 at 23:11
  • This would lead to believe it's a permissions problem in IIS? – snackboy Jul 10 '23 at 23:12
  • An important clue (?): If the .cfc that does the `fileRead` is called from a .cfm, using `cfhttp`,`createObject`,`invoke`, it works with no error. But if called via [url]/test.cfc?method=getData or (as the app was initially doing) via `$http` (AngularJS), the error is generated. Both of those methods are using the same url. It also fails if called from another `cfc`. – snackboy Jul 11 '23 at 14:10
  • Also, I tested FileWrite - it behaves the same way as the FileRead - the file is written but the 500 error is thrown. – snackboy Jul 11 '23 at 14:39
  • 1
    Bypass the IIS error handler by putting `` under `configuration > system.webServer` in the `web.config` (root folder of your site). This will allow CF to properly spill the status code. – Alex Jul 11 '23 at 15:33
  • I checked the web.config (thanks!) between prod and dev. There were differences in how requests and errors are handled. I've asked the network admin to restart whatever needs to be restarted for the web.config to take affect. Hopefully I'll have an update soon. – snackboy Jul 11 '23 at 16:25
  • I made the change, and the CF service was restarted. But there was no change in the error or information about the error. Unfortunately, because this is a production system, I can't troubleshoot by restarting the service at will. I think that because the request is returning a 200 status code, that nothing is going to trigger the additional information. The 500 error seems to be appended to the data coming back from the request. – snackboy Jul 12 '23 at 17:40

2 Answers2

1

Given what's been said in the dozens of comments (or your original and the for-now-only other answer), I'd wonder what you if you try adding a returnformat querystring to the call of the CFC as a URL, to change the format of what's being returned. You could try https://ourdoman.edu/fileReadTest.cfc?method=test&returnformat=plain, for example, or returnformat=json.

As you may know, the default is for CF to return such results as wddx (which is xml). Maybe that's somehow leading to your problems. I can't fathom what that could be, but it could at least give you/us a clue. And if somehow either variant works better, you could also set the "correct" returnformat as an argument of the same name on the method definition. (I have a 2017 blog post on how to do that in a script-based function definition. And to be clear, I do see you define the test function's return type to be string, which is a separate matter.)

Either way, it will be interesting to hear if this helps at all.

charlie arehart
  • 6,590
  • 3
  • 27
  • 25
  • Thanks Charlie. As a matter of practice I do specify the returnType and returnFormat in the function declaration. I added the url params you suggested to the request, and there was no change other than JSON replacing the wddx. Four important(?) clues: 1) this happens on production (not dev); 2) it also happens with fileWrite; 3) FileRead/FileWrite work fine via CFM; 4) The 500 error is appended to the response data and has a 200 status code. If this were a CFC returning data issue, our entire system wouldn't work. I think CF is expecting something from FileRead it's not getting. – snackboy Jul 13 '23 at 03:55
  • Thanks for the update. But to be clear there was no returnFormat in the example above. Anyway, OK on confirming it didn't help. (As for why it may have, I understand entirely how the error is appending the 500. And no, I'd not have presumed this explanation would mean your entire system would not work.) But it was worth a shot proposing it. Hope you find the solution. – charlie arehart Jul 14 '23 at 04:39
  • Thanks Charlie. Yeah, I need to clarify the above test code a bit for any future folks reading the thread. Our next step is to see if we can get our test instance up to production standards and run the tests from there. – snackboy Jul 14 '23 at 14:56
0

Your method signature says it is returning a string. However you aren't returning a string could this be the issue?

  • Good catch on the coding mistake. But unfortunately that was not the issue. I'll update the question accordingly. – snackboy Jul 11 '23 at 03:25
  • Well I don't think your problem is going to be an IIS issue, but IIS is most likely covering up the problem by intercepting the 500 error and displaying it's own message. I would then follow up and look at your entire life cycle of your request.... Application.cfc is there a onRequestStart, onRequest, onRequestEnd, onCFCRequest. Do those do anything interesting or weird? – Michael Schmidt Jul 11 '23 at 12:27
  • The application.cfc doesn't have anything for the onRequestStart/End. I even put code in them to make sure they were firing, and both do without error. The code that revealed this issue has been in production since 2021. It was only until after the upgrade to CF2023 that it started to show this error. In our development environment the code runs perfectly fine. However, it's internally facing meaning that it cannot be accessed outside the network. This leads me to believe the issue is not CF specific but something server (perhaps Java) or network related. – snackboy Jul 11 '23 at 13:54
  • I would simplify your test ... `component { remote string function test() { return "Flying Monkeys"; } }` – Michael Schmidt Jul 11 '23 at 14:04
  • If I take out the fileRead, it works fine. What's interesting/weird (posted a sample as an update to the question) that the file is read, and returned, but CF is also returning the 500 error. Also, the fileRead works fine when called from a .CFM. It is when the CFC is called via URL or from (AngularJS) $http that the issue occurs. – snackboy Jul 11 '23 at 14:18