Copy link to clipboard
Copied
I'll see if I can explain:
/application.cfc
/api.cfc
/web.config
If you call a URL structured in this manner "domain.com/method/function" then I have a url redirect in web.config that translates that to /api.cfc?method=init&function=functionname.
The api.cfc has an init handler that takes those URL params and calls the actual private function it has that matches those needs. This is heavily simplified, but you get the idea.
The application.cfc is a shell of a file, nothing is done in there at all. Just function outlines.
This ALL works fine except when the CFC itself returns a CF error. If you call the URL directly (as it was explained above) with a GET then you see the error. IF you use a HTML form to post to the page in a browser, you see the error. However if you POST data to that URL using CFHTTP then the connection times out based on the CFHTTP timeout param. The response is "connection timeout" in the CFHTTP vars and status code 200.
This is stumping me.
Copy link to clipboard
Copied
Could you show us your cfhttp code?
Copy link to clipboard
Copied
I'll see if I can simplify:
Web.config takes a regex that basically evaluates to */* as a wildcard. So someone calls bob.com/test/this then we get vars "test" and "this" forwarded to something like api.cfc?method=init&var1=test&var2=this.
Api.cfc has an init method which validates url vars, verb used to call the page, etc.
To test the API I have a page on another app server calling the public API URL using CFHTTP and POST method. Nothing strange here, calls the URL and posts body data.
Any time the api.cfc has a CF error (errors that aren't handled by application.cfc onError(), so gray CF output) the CFHTTP call times out. No matter what the timeout setting, it will timeout.
web.config rewrite rule
<rule name="API" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^v1/([^\\/?%*:|"<>\.]+)/([^\\/?%*:|"<>\.]+)$" />
<action type="Rewrite" url="/v1/api.cfc?method=init&function={R:1}_{R:2}" />
</rule>
Just a bit of the api.cfc file, you can see how the init function is structured.
component {
/***********
INIT
***************/
remote void function init() {
this.calledFunction = '';
this.apiUserID = 0;
//Make sure our URL var exists from the URL rewrite
if (!StructKeyExists(url, "function")) {
abort;
}
Sample of the CFHTTP remote call:
<cfhttp method="post" url="https://api-dev.boompayments.com/v1/customer/auth" timeout="3">
<cfhttpparam type="body" value="#cfsavecontent#">
</cfhttp>
Nothing really out of the ordinary except I have never used this method with the web.config and rewriting to a CFC. Everything works as long as api.cfc does not return a CF gray error page. I haven't messed with any of the CF admin error handling settings. This is a dev server so robust handling is on but in prod that would be off. I can test that on dev and see if that changes anything but even with the CF error I'd like to not timeout connections.
Copy link to clipboard
Copied
Thanks for the code excerpts. Errors that ColdFusion has to handle outside the usual mechanisms, onError, try-catch, cferror or site-wide handler are indeed out there in the wild. It just might be that, for whatever reason, ColdFusion gets itself in a twist when composing a complex error response. Think of a stray thread that hangs.
You might be able to force a response by putting your cfhttp tag in a try-catch, as follows:
<cftry>
<cfhttp throwOnError="yes">
</cfhttp>
<cfcatch type="any">
<cfdump var = "#cfcatch#">
</cfcatch>
</cftry>
Copy link to clipboard
Copied
Two issues with that... firstly, the timeout is still the limiting factor so the delay until that is reached is unacceptable. Second, throwonerror does not seem to trigger in the event of a timeout. The issue really is that the cfhttp call should return the page content (the CF error) immediately. Sure, I should not have a CF error and I'll have error handling in place, but I can't imagine any other http connection method (curl, wget, etc) would have this issue.
Copy link to clipboard
Copied
I agree with your point. However, to be fair to ColdFusion, there is more to the story.
That timeout remains a limiting factor is not an issue. It is so by design. It is the maximum time period within which ColdFusion must respond to the request. Unless, of course, an error occurs - and ColdFusion throws it! - before the timeout is reached. In other words, if everything is working normally, the throwonerror would not trigger in the event of a timeout.
Now the explanation for the proviso I marked in bold. This story is complicated by the fact the cfhttp request may in fact exceed the timeout, by far, without ColdFusion throwing an error. For tags such as cfhttp and cfquery, the underlying Java Virtual Machine generates so-called native threads. ColdFusion cannot stop them because they are beyond its influence. If any such threads were to run indefinitely, ColdFusion would have no choice but to wait for them.
I suggested the try-catch so that you would at least get information about an error, should it percolate up the stack.