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 RIA Unleashed (Nov. 2010) with: Bob Silverberg and Carol Loffelmann and Vicky Ryder

Throwing And Catching A File Using CFHttp For Both Actions

By Ben Nadel on
Tags: ColdFusion

I can't remember where I heard this, but not so long ago I heard or read about someone who wanted to send a file to another server using CFHttp. He didn't have any FTP stuff set up, so that was they best idea he had. This seemed like a fun little piece of functionality to test as I have never done that before.

I set up two pages: cfhttp_throw.cfm and cfhttp_catch.cfm. As you can probably guess, the cfhttp_throw.cfm takes a file from the local file system and "posts" it to the cfhttp_catch.cfm. The cfhttp_catch.cfm file then "uploads" it to its server and echoes back the file name as it was stored on the new machine.

This was suprisingly easy. I have not used CFHttp all that extensively and in about 10 minutes I worked out something that did just what I wanted to do. And, in the process, I used a CFHttpParam tag of type "File" which I had never done before. I have to go back and check out the rest of the CFHttpParam types to see what else I am missing (damn you ignorance!).

Here is the cfhttp_throw.cfm code. It doesn't have all the CFTry / CFCatch tags that probably should be used, but for this proof of concept, it was not necessary:

  • <!---
  • Submit the file the CFHTTP_Catch.cfm file. Notice that we
  • are sending the file via a CFHttpParam FILE tag. By using
  • this file param, CFHTTP automatically sends all form
  • fields as multi-part form data; therefore, we do NOT need
  • to specify the "multipart='true'" CFHttp attribute.
  • --->
  • <cfhttp
  • url="http://swoop/..../cfhttp_catch.cfm"
  • method="POST"
  • useragent="Mozilla/5.0 Gecko/20070309 Firefox/2.0.0.3"
  • result="objHTTP">
  •  
  • <!---
  • Send along a file via the FORM post. This acts the same
  • as a stanard form Input type="file" field and can be
  • handled as such on the "Catch" page.
  • --->
  • <cfhttpparam
  • type="FILE"
  • name="file"
  • file="#ExpandPath( './test.jpg' )#"
  • />
  •  
  • </cfhttp>
  •  
  •  
  • <cfoutput>
  •  
  • <h4>
  • CFHttp Post Result:
  • </h4>
  •  
  • <p>
  • #objHTTP.FileContent#
  • </p>
  •  
  • </cfoutput>

And, here is the cfhttp_catch.cfm code:

  • <!--- Kill extra output. --->
  • <cfsilent>
  •  
  • <!---
  • Param the form fields. Since this data is coming via
  • a CFHTTP "Post" we can operate as if it was a standard
  • form submission.
  • --->
  • <cfparam
  • name="FORM.file"
  • type="string"
  • default=""
  • />
  •  
  •  
  • <!--- Try to upload the file. --->
  • <cftry>
  •  
  • <!---
  • Upload the file. When defining the CFFile, we can
  • treat the posted file as if it was submitted via a
  • standard File Input (since it was posted as a FILE
  • using CFHttpParam).
  • --->
  • <cffile
  • action="UPLOAD"
  • filefield="file"
  • destination="#ExpandPath( './files/' )#"
  • nameconflict="MAKEUNIQUE"
  • />
  •  
  •  
  • <!---
  • Echo back the name of the file as it has been
  • saved to the server.
  • --->
  • <cfcontent
  • type="text/plain"
  • variable="#ToBinary( ToBase64( CFFILE.ServerFile ) )#"
  • />
  •  
  •  
  • <!---
  • Catch any errors that were thrown during the
  • file upload.
  • --->
  • <cfcatch>
  •  
  • <!--- Echo back the error message. --->
  • <cfcontent
  • type="text/plain"
  • variable="#ToBinary( ToBase64( CFCATCH.Message ) )#"
  • />
  •  
  • </cfcatch>
  • </cftry>
  •  
  • </cfsilent>

That was pretty cool. I like that using the proper CFHttp / CFHttpParam tags, your target page can act as if the request was coming from a standard Form-action page with standard FORM-scoped values. I think it's totally awesome that CFFile can actually upload the file that is posted to it. Very cool.




Reader Comments

What is the deal with this?

#ToBinary( ToBase64( CFFILE.ServerFile ) )#

CFFILE.* should all be strings. So why not just output as is?

Reply to this Comment

@Ray,

Cause I am a sick person .... the Variable attribute of CFContent only takes binary data and won't allow string data unless you convert it to binary first (hence the ToBinary stuff). Sure, I could just output it after the CFSilent, but I don't think that looks as nice.... Like I said, I am sick (in the head) and code formatting is that special to me :)

Reply to this Comment

Hey Ben,

I've been playing around with drag-n-drop uploads using jQuery and XMLHttpRequest Level 2. Check out: http://onehub.com/blog/posts/designing-an-html5-drag-drop-file-uploader-using-sinatra-and-jquery-part-1

Basically it's a PUT method and not sure if this relates with exactly what you are doing here, but it seems to be somewhat the same.

I can get the PUT to work great, but I'm having problems with the "catcher" file, since obviously this is not using traditional form fields. Have you had any experience playing around with this yet?

Reply to this Comment

@Ben

I think I answered my own question.

Looks like you can grab the XHR data using ColdFusions "GetHttpRequestData()" function. So to capture the file and save you would do something like this:

<cfset xhr_data = GetHttpRequestData() />
<cffile action="write" file="#ExpandPath('.')#/#CGI.HTTP_X_FILENAME#" output="#xhr_data.content#">

p.s. this doesn't work so well on older browsers.

Reply to this Comment

@Doug,

I've played around very briefly with the XMLHttpRequest 2 API; from the little that I've read up on it, you should be able to actually create a multi-part form request that acts juts like a native request. I think this is the blog post that I learned from:

http://blog.igstan.ro/2009/01/pure-javascript-file-upload.html

Of course, this only works in like FireFox 3.6 which is like the most current few releases.

Reply to this Comment

@Ben,

Cool, I'll check it out.

The one I linked to above works in everything except IE. I've gotten it to work with the "PUT" method, but I'm struggling a little bit with the normal "POST" fallback option.

I'm sure I'll figure it out. Thanks.

Reply to this Comment

@Doug,

If you have your stuff working in everything but IE, disregard my link. I believe the example in the link I sent you *only* works in the latest Firefox releases. Sounds like you are on a better track than me.

Reply to this Comment

This is a good post! This is about sending a file with a http post request from Server A to Server B. I have a question about doing something slightly different.

what if server A wants to download a file from server B via an http request. so in essennce an http download. Is it something to do with what you set in cffilecontent response type? How nice it would be if there was a working example somewhere.

Thanks!

Reply to this Comment

I guess i figured it out. I would need this on the httpResponse

<cfheader name="Content-Disposition" value="inline; filename=testing.doc">
<cfcontent type="application/msword" file="#fileName#" deletefile="no">

and something like this on the requester file.

<cfscript>
ioOutput = CreateObject("java","java.io.FileOutputStream");
ioOutput.init("C:\...\testing.doc");
objHTTP.Filecontent.writeTo(ioOutput);
ioOutput.close();
</cfscript>

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.