Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
I am the chief technical officer at InVision App, Inc - a prototyping and collaboration platform for designers, built by designers. I also rock out in JavaScript and ColdFusion 24x7.
Meanwhile on Twitter
Loading latest tweet...
Ben Nadel at CFUNITED 2008 (Washington, D.C.) with:

Dumping Out The CGI Scope Does Not List All Available CGI Values In ColdFusion

By Ben Nadel on
Tags: ColdFusion

I had an interesting / unfortunate journey yesterday, concerning the CGI scope. I was trying to access a value that was being passed-through by the load balancer; and, since I had never dealt with this value before, I naturally tried to CDump-out the CGI scope to see what it would be. Unfortunately, the value was not present in the CGI dump. This lead to several support tickets, which turned out to be useless since, as I am just now learning now for the first time, the CGI scope doesn't "report" all of its available keys.

Unlike a normal Struct in ColdFusion, it looks like the CGI scope will only report on a known subset of key values. You can still ask the CGI scope for which ever key you want; but, as far as CFDump and key-loops are concerned, you may only be seeing a part of the whole picture.

To demonstrate, I'm going to try to "find" the CGI value, "document_root". I will do this though both direct key reference as well as key reporting:

  • <cfscript>
  •  
  • target = ucase( "document_root" );
  •  
  • // Get the document root directly from the CGI scope.
  • writeOutput( "#target#: #cgi[ target ]#" );
  •  
  • writeOutput( "<br />" );
  • writeOutput( "- - - - - - - - - - - - - - - - -" );
  • writeOutput( "<br />" );
  •  
  • // Now, try to get the value by looping of the CGI key list
  • // and checking to see if the key matches our target.
  • for ( key in cgi ) {
  •  
  • writeOutput( key );
  •  
  • if ( key == target ) {
  •  
  • writeOutput( ": #cig[ key ]# <br />" );
  •  
  • } else {
  •  
  • writeOutput( ": . . . <br />" );
  •  
  • }
  •  
  • }
  •  
  • </cfscript>

As you can see, we try to loop over the CGI scope, looking for the "document_root" key. And, when we run the above code, we get the following output:

DOCUMENT_ROOT: /Sites/bennadel.com
- - - - - - - - - - - - - - - - -
HTTP_USER_AGENT: . . .
WEB_SERVER_API: . . .
PATH_TRANSLATED: . . .
CONTENT_TYPE: . . .
HTTP_ACCEPT_LANGUAGE: . . .
HTTP_REFERER: . . .
HTTP_ACCEPT: . . .
CERT_SERVER_ISSUER: . . .
CERT_SERVER_SUBJECT: . . .
HTTP_ACCEPT_ENCODING: . . .
SERVER_SOFTWARE: . . .
SERVER_NAME: . . .
CF_TEMPLATE_PATH: . . .
CERT_FLAGS: . . .
HTTPS_SERVER_ISSUER: . . .
CONTEXT_PATH: . . .
HTTP_COOKIE: . . .
SERVER_PROTOCOL: . . .
CERT_SECRETKEYSIZE: . . .
REQUEST_METHOD: . . .
HTTPS_SECRETKEYSIZE: . . .
AUTH_PASSWORD: . . .
HTTPS: . . .
CERT_SERIALNUMBER: . . .
CERT_SUBJECT: . . .
SERVER_PORT: . . .
CERT_KEYSIZE: . . .
SCRIPT_NAME: . . .
REMOTE_ADDR: . . .
SERVER_PORT_SECURE: . . .
REMOTE_HOST: . . .
HTTPS_KEYSIZE: . . .
HTTP_HOST: . . .
HTTP_CONNECTION: . . .
AUTH_USER: . . .
REMOTE_USER: . . .
PATH_INFO: . . .
QUERY_STRING: . . .
CERT_ISSUER: . . .
CERT_COOKIE: . . .
HTTPS_SERVER_SUBJECT: . . .
GATEWAY_INTERFACE: . . .
AUTH_TYPE: . . .
CONTENT_LENGTH: . . .

As you can see, while we were able to directly reference the "document_root" key, the CGI scope does not "report" it as a known value. Unfortunately, this little quirk of the language cost me a few hours of head-scratching and support tickets. Hopefully this will prevent you from doing the same!




Reader Comments

This is also the reason that the CGI doesn't throw errors if you request variables that don't actually exist. If you ask for CGI["OMGTHISISBAD"] all you get is an empty string, not some kind of undefined error.

Reply to this Comment

@Jon,

Word. And, I actually like that particular feature! I find that it makes easier to write conditionals without having to do things like:

if ( structKeyExists( cgi, "xyz" ) && len( cgi.xyz ) ) { .. }

... just simply go:

if ( len( cgi.xyz ) ) { .. }

Much easier :)

Reply to this Comment

I found this issue a couple years ago when I noticed one of custom Apache CGI variables wouldn't show up in our CGI dumps.

In order to get the custom variable to show up, I used structCopy/structInsert and then dumped the new customCGI scope:

  • <cfset customCGI = structCopy(cgi) />
  • <cfset structInsert(customCGI,"WEB_ENV",cgi.web_env) />
  • <cfdump var="#customCGI#" label="CGI object" />

Now all CGI variables are dumped. :-)

Reply to this Comment

@David,

Thanks for the typo. I didn't catch it because the IF-statement never fires (hence no exception). I'll fix that after work.

Reply to this Comment

This makes no sense to me.

A scope that behaves in a unique manner to other scopes. I'm find that scopes have some core differences, like whether they are persistent or not, but when I tell something to dump, you best give up the goods... and NOT be taking a cut off the top.

Gotta say, I'm not liking CGI acting in this manner. If the variables are there, show them. If you reference a variable that doesn't exist, throw an error (even to Ben's dismay) :) One of the core truths we try to hold onto when coding is that we stay consistent with our methodologies and don't invoke a haphazard logic that does Action A THIS way, but would in other instances perform Action A THAT way.

Consistency!

Reply to this Comment

@Aaron,

I'm with you; I absolutely hate that CGI gives back empty strings. Its essentially a unique behavior that goes against all documentation and language expectations.

Reply to this Comment

@Aaron, @Jon,

It would be cool if ColdFusion implemented the "Elvis Operator" that does a sort of conditional check:

  • var value = structKeyExists( cgi, "foo" ) ? cgi.foo : "";
  •  
  • var value = cgi.foo ?: ""

I saw this in a presentation on Groovy. It's sort of a short-hand for the conditional check / ternary operator.

Reply to this Comment

@Aaron @Jon

Agreed, it makes no sense. Has someone raised a bug with adobe/railo that I can vote on?

Really the only way to find out what is there right now is to do a brute force on the cgi scope to see what is hidden away. Not cool :(

Reply to this Comment

@Ben,
CF9 & CF10 both support the "Elvis" syntax that you list -- I've got production code running it now. I was introduced to it by a front-end guy who asked if it was possible and I was like -- what is that?!?

Turns out it worked and I said goodbye to IIF and silly if else variable sets forever!

That syntax is what IIF dreams of at night...

Reply to this Comment

@Ben,

The closest I use is:

<cfset x = iif( structKeyExists( CGI, 'foo' ), de( 'this' ), de( 'that' ) ) />

Seems to work well enough, but it's not as sunccinct. :)

Reply to this Comment

Fyi you can get all those vars via any decent debugging tools that shows u all http headers such as chrome developer tools and several firefox plugins

Reply to this Comment

@snake,

Absolutely. I've sent the developers of Firebug and the Web Developer Toolbar money because I freaking LOVE those tools, but it *is* still 1 more step you'd have to take to make up for an odd shortcoming with ColdFusion.

Maybe introduce a new application variable, if Adobe wants to keep it like it is so bad.

<cfset this.GimmeAllDaDangVarsInDaClientScopeWhenIAskFerDem = true />

Reply to this Comment

@Aaron,

If you have those tools Installed which I think most devs do now, it's not really an extra step. And tbh I think anyone who is not a newb must be used to the deficiencies in cf by now or switched to Railo :)

Reply to this Comment

@Jason The "Elvis operator" is the "?:" in Ben's second example. CF9 doesn't support this and I don't believe CF10 does either, but Railo 4.1 does.

I think you must mean the "ternery operator" in Ben's first example.

Reply to this Comment

Coldfusion absolutely has the ternary operator with <boolean expression> ? <true op> : <false op>. See Ben's page on it at:

http://www.bennadel.com/blog/1643-Learning-ColdFusion-9-The-Ternary-Operator.htm

We use Smart Cards here to login in and the person's info is dumped into variables in the CGI scope with the single sign on. Unfortunatley not all the variables show up in Coldfusion. I wrote an ASP page to dump all of them out and they are all there in the ASP page. However in Coldfusion, 3 of them are missing such as the person's middle name and couple of others. I don't know if this is because of tomcat or Coldfusion.

Reply to this Comment

deja vu ..
i was really convinced you already posted something like this many moons ago, but since the collective memory of the human race (google) does not record it, it does not exist

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.