Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading a file with cfhttp appends a newline (even on binary files)

Update: I've found a workaround. If I submit a dummy form field along with the file, it works. Is this a ColdFusion bug, or is there something in the HTTP spec that says forms must contain at least one non-file form field?

Update 2: I'm convinced this is a ColdFusion cfhttp bug. This is based on Leigh's answer and the fact that I used the code below to submit a form with only the file element using javascript, and it works fine:

<form enctype="multipart/form-data" action="<cfoutput>#CGI.PATH_INFO#</cfoutput>" method="POST" name="theForm">
  <input name="theFile" type="file" /><br/>
</form>
<a href="#" onclick="document.theForm.submit()">submit</a>

I'm running into a problem uploading files from a ColdFusion server to another webserver. It seems that cfhttpparam type="file" is indiscriminately appending a newline (carriage return and line feed) to the end of the file. This is breaking binary files. This does not happen when I manually upload the file via form field. I have tried with and without mimetype parameter, and I've tried lying about mimetype with various binary formats (exe, zip, jpg), but nothing has worked. Is there some parameter I'm missing, or is this a bug in ColdFusion? (I'm running on CF 8.0.1.195765 on WinXP.)

Below is test code I'm using, it just uploads the file to the same directory. The manual upload works, but the server-based upload ends up appending a CRLF to the file.

<cfset MyDir = "C:\test" />
<cfset MyFile = "test.zip" />

<cfif IsDefined("Form.TheFile")>
  <cffile action="upload" fileField="theFile" destination="#MyDir#" nameConflict="MakeUnique" />
<cfelse>
  <cfhttp url="http://#CGI.SERVER_NAME##CGI.SCRIPT_NAME#" method="POST" throwOnError="Yes">
    <cfhttpparam type="file" name="theFile" file="#MyDir#\#MyFile#" />
  </cfhttp>
</cfif>

<html><body>
<h2>Manual upload</h2>
<form enctype="multipart/form-data" action="<cfoutput>#CGI.PATH_INFO#</cfoutput>" method="POST">
  <input name="theFile" type="file" /><br/>
  <input type="submit" value="Submit" />
</form>
</body></html>
like image 527
Kip Avatar asked Sep 17 '10 20:09

Kip


2 Answers

or is there something in the HTTP spec that says forms must contain at least one non-file form field?

I do not know for certain. But according to these definitions it seems like a POST containing only a file input should be valid. So I suspect the problem may be CFHTTP in ACF.

According to Fiddler the raw content from the cfhttp call in ACF contains an extra new line just before the end boundary (0D 0A in hex view). But under Railo it does not. So I think ACF's cfhttp might be the culprit.

Sample Code:

<cfhttp url="http://127.0.0.1:8888/cfusion/receive.cfm" method="post">
    <cfhttpparam name="myFile" type="file" file="c:/test/testFile.zip" mimetype="application/octet-stream" />
</cfhttp>

Results Railo 3.1.2

POST /railo/receive.cfm HTTP/1.1
User-Agent: Railo (CFML Engine)
Host: 127.0.0.1:8888
Content-Length: 382
Content-Type: multipart/form-data; boundary=m_l7PD5xIydR_hQpo8fDxL0Hb7vu_F8DSzwn

--m_l7PD5xIydR_hQpo8fDxL0Hb7vu_F8DSzwn
Content-Disposition: form-data; name="myFile"; filename="testFile.zip"
Content-Type: application/octet-stream; charset=ISO-8859-1
Content-Transfer-Encoding: binary

PK
&�1=�cN'testFile.txtTestingPK
&�1=�cN' testFile.txtPK:1
--m_l7PD5xIydR_hQpo8fDxL0Hb7vu_F8DSzwn--

Results ACF (versions 8 and 9)

POST /cfusion/receive.cfm HTTP/1.1
Host: 127.0.0.1:8888
... other headers removed for brevity ....
Content-type: multipart/form-data; boundary=-----------------------------7d0d117230764
Content-length: 350

-------------------------------7d0d117230764
Content-Disposition: form-data; name="JobFile"; filename="c:\test\testFile.zip"
Content-Type: application/octet-stream

PK
&�1=�cN'testFile.txtTestingPK
&�1=�cN' testFile.txtPK:1

-------------------------------7d0d117230764--
like image 98
Leigh Avatar answered Oct 06 '22 01:10

Leigh


Maybe Railo 3.1.2 and ColdFusion 9 handle this a bit differently, but your code looks a bit incorrect for me.

Your CGI.PATH_INFO is not applicable here.

While browser is smart enough to use path without hostname, CFHTTP feels better with full hostname + script path + script name. Note: cgi.SCRIPT_NAME worked in CF9, Railo required cgi.SERVER_NAME to be prepended, though I feel this more correct in general.

That's why a bit modified version of the code works fine for me. Zip file is uploaded and posted without being corrupted.

Form:

<form enctype="multipart/form-data" action="<cfoutput>#cgi.SCRIPT_NAME#</cfoutput>" method="POST">
  <input name="theFile" type="file" /><br/>
  <input type="submit" value="Submit" />
</form>

CFHTTP:

  <cfhttp url="#cgi.SERVER_NAME##cgi.SCRIPT_NAME#" method="POST" throwOnError="Yes">
    <cfhttpparam type="file" name="theFile" file="#MyDir#/#MyFile#" />
  </cfhttp>

Hope this helps.

like image 33
Sergey Galashyn Avatar answered Oct 06 '22 00:10

Sergey Galashyn