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 Scotch On The Rock (SOTR) 2010 (London) with: Matthew Bourke

Using CFHTTP GetAsBinary To Normalize HTTP Response File Content Format

By Ben Nadel on
Tags: ColdFusion

Earlier this week, I was building a gateway for the Amazon Simple Storage Service (S3) API. As part of my testing, I tried to read an image in from Amazon S3 and then write it to the browser using the CFImage tag [action=writeToBrowser]. And, while this worked last week, this week I was getting the following ColdFusion error:

The cfimage tag accepts only those ColdFusion variables that contain Base64 strings, BLOBs, Byte arrays or other images as inputs.

I wanted to see if this was an issue specific to Amazon S3; or, if there was some problem with my code. And so, I tried to isolate the problem down to a simple CFHTTP request to my local server:

  • <!--- Build our "Test" image url on the local server. --->
  • <cfset imageUrl = (
  • "http://" &
  • cgi.server_name &
  • getDirectoryFromPath( cgi.script_name ) &
  • "monkey.jpg"
  • ) />
  •  
  • <!--- Request the file content of the image. --->
  • <cfhttp
  • result="get"
  • method="get"
  • url="#imageUrl#"
  • />
  •  
  • <!--- Write the image to the browser. --->
  • <cfimage
  • action="writetobrowser"
  • source="#get.fileContent#"
  • />

Here, I'm just requesting a JPG image from the same folder (over HTTP) and then attempting to output it. And since the HTTP request is reading a "binary" object, the CFImage tag should work. However, I get the same ColdFusion error as above. So, it has nothing to do with the Amazon S3 API.

When I went to CFDump the HTTP response, I noticed that my fileContent variable, which should have been a ByteArray (ie. a binary value) was, in fact, an instance of the Java object:

java.io.ByteArrayOutputStream

When I saw this, I realized what I was missing in my earlier code snippet - the GetAsBinary attribute on the CFHTTP tag. When you omit this attribute, ColdFusion attempts to convert the HTTP response into an "appropriate" data type. And, as Adam Cameron pointed out a few months ago, ColdFusion doesn't always get this right.

To fix my problem, I added the GetAsBinary="yes" attribute to the CFHTTP tag such that my response would always be a byte array, even if the remote resource was a text value. Since ColdFusion can convert binary data into string data, this seems like an easy way to normalize the CFHTTP response content format.

To see this in action, the following code makes a request for a "remote" XML file and reads it in as a binary object. Then, I'm going to convert that binary to a string, parse it into an XML document, and extract one of the XML nodes:

  • <!--- Build our XML request url on the local server. --->
  • <cfset dataUrl = (
  • "http://" &
  • cgi.server_name &
  • getDirectoryFromPath( cgi.script_name ) &
  • "data.xml"
  • ) />
  •  
  • <!--- Request the "remote" XML file as a binary value. --->
  • <cfhttp
  • result="get"
  • method="get"
  • url="#dataUrl#"
  • getasbinary="yes"
  • />
  •  
  • <!---
  • Parse the response into an XML document. Notice that I have to
  • tell ColdFusion to convert the binary value to a string.
  • --->
  • <cfset response = xmlParse( charsetEncode( get.fileContent, "utf-8" ) ) />
  •  
  • <!--- Extract the response message node. --->
  • <cfset message = xmlSearch( response, "string( //Message/text() )" ) />
  •  
  • <cfoutput>
  •  
  • Message: #message#<br />
  •  
  • </cfoutput>

And, when I run the above code, I get the following XML node output:

Message: Woot, I am XML!

This may seem like overkill - always returning CFHTTP file content as a byte array. But, if you're dealing with a remote API that returns various types of content, this is an easy way to ensure that you're always parsing a response with a known format.




Reader Comments

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.