Remote Function Content-Type difference between Lucee and ColdFusion

A continuation of my blog with a better solution… LOL

Due to my issues with struct handling in the OnCFCRequest method, I thought I’d try a slightly different approach. Basically, I ignored onCFCRequest() and made use of onRequestEnd() instead. It’s similar to the other approach with the added benefit that I don’t have to interrupt the calls and inject my own handler for the content. It can do whatever it was doing before and now I can simply change the Content-Type header in certain circumstances.

Here’s the new method that seems to be doing exactly what I need so far in basic testing.

Application.cfc in OnRequest():

if (ListLast(cgi.script_name, ".") == "cfc") {
	contentTypeHandler();
}

And then I added this function in Application.cfc to handle the header conversions. I’m sure it can be optimized, extended, etc but it’s functional right now and that’s the most important thing for me at the moment.

/* @hint Sets headers in certain scenarios to mimic ColdFusion behavior */
private void function contentTypeHandler()
output="false" {
	param name="url.fallbackToACF", type="boolean", default=true;
	param name="request.fallbackToACF", type="boolean", default=true;

	if (!request.fallbackToACF) {
		// Using request as priority in case we want to FORCE a specific content-type internally
		return;
	} else if (!url.fallbackToACF) {
		// Otherwise, if the caller wants to adjust the ouput, allow them to do that here
		return;
	}

	// Get cfc name & path in dot-notation formation
	var cfcName = cgi.SCRIPT_NAME;

	// Drop .cfc from path and change to dots
	cfcName = Reverse(ListRest(Reverse(cfcName), "."));
	cfcName = listChangeDelims(cfcName, ".", "\/");

	// Get method name from url params
	var method = "";

	for (item in ListToArray(cgi.query_string, "&")) {
		var data = ListToArray(item, "=");

		if (data.len() == 2) {
			if (data[1] == "method") {
				method = data[2];
				break;
			}
		}
	}

	if (!Len(method)) {
		// No method discovered so carry on as-is
		return;
	}

	// Doing this in case it wasn't created during app start (ie code added after app started?)
	if (!application.keyExists('cfc_cache')) {
		application.cfc_cache = {};
	}

	// Populate cache data for this request if needed
	if (!application.cfc_cache.keyExists(cfcName)) {
		try {
			application.cfc_cache[cfcName] = {
				component = createObject("component", cfcName),
				meta = {
					returnFormat = ""
				}
			};
		} catch (any e) {
			// This could happen if the requested template doesn't exist or is just broken for some reason
			return;
		}

		// Now for the part we really need: metadata
		application.cfc_cache[cfcName].meta.append(
			getMetaData(application.cfc_cache[cfcName].component[method]),
			true
		);
	}

	// For now, just modifying json output but might extend or adjuist later as needed
	if (application.cfc_cache[cfcName].meta.returnFormat == "json") {
		cfheader(name="Content-Type", value="text/html");
	}
}

Now I can mimic the (likely incorrect) ColdFusion behavior that sends returnFormat=“json” content back to the call as “text/html”. But I’m also able to override this behavior as needed through either url or request variables (in case I want to force “correct” behavior). Thus far, it’s working splendidly and carry on with my other testing without having to change json or js behaviors to compensate for the difference between Lucee and ColdFusion. So I’m much more optimistic that this may be achievable.

1 Like