Search code examples
web-servicesfile-uploadcoldfusion

Enctype issue when I try to upload a file with a Coldfusion webservice


Can't get to work a Coldfusion webservice that uploads a file in an external server.

My application runs in "Server A" and the file repository (external server) is in "Server B"

The template (inicio.cfm) which contains the form with the <cfinput type="file"> to select the client's file to be uploaded, is stored in "Server A". This template performs more tasks than just show the upload form. It performs calculations, queries, etc. outside the form's code block. Also, the action page of this form is the template itself (because of my application's needed tasks).

The first code line of my form definition is (inside inicio.cfm):

<cfform method="post" name="AltaConvocatoria" enctype="multipart/form-data">

Which demonstrate that I'm using the right enctype definition.

In the other hand, stored in "Server B" is my Coldfusion component or webservice (alta_ga.cfc) which only task is to upload the file selected by user in "inicio.cfm" form and rename it.

Here's alta_ga.cfc code:

<cfcomponent>

    <cffunction access="remote" returntype="void" name="cargaAnuncio">

        <cfargument name="destinoAnuncio" required="yes" type="string">

        <cfargument name="PrefijoNvoNombre" required="yes" type="string">

        <cffile action="upload"
        fileField="str_ArchivoAnuncio"
        destination="#destinoAnuncio#"
        nameconflict="Overwrite">
        <cfset NvoNomAnuncio = #PrefijoNvoNombre# & #Right(cffile.ClientFile, 5)#>

        <cfset viejoNombre1 = #destinoAnuncio# & #cffile.ClientFile#>

        <cffile
        action = "rename"
        destination = "#NvoNomAnuncio#"
        source = "#viejoNombre1#">

    </cffunction>

</cfcomponent>

For that pupose, I invoke the webservice from the form's action code block in inicio.cfm with this:

<cfinvoke webservice="http://192.168.208.128/podi/mgmt/alta_ga.cfc?wsdl" method="cargaAnuncio" >
    <cfinvokeargument name="destinoAnuncio" value="#form.destinoAnuncio#" />
    <cfinvokeargument name="PrefijoNvoNombre" value="#form.PrefijoNvoNombre#" />
</cfinvoke>

When I try to load a file using my form's template inicio.cfm I get this message:

Cannot perform web service invocation cargaAnuncio. The fault returned when invoking the web service operation is: '' podi.mgmt.PodiMgmtAlta_gaCfcCFCInvocationExceptionException: coldfusion.tagext.io.FileUtils$CFFileNonMultipartException : Invalid content type: application/soap+xml; charset=UTF-8; action="urn:cargaAnuncio".The files upload action requires forms to use enctype="multipart/form-data".]

All the arguments and variables that I'm using are correct, because I tested the webservice as a local component (stored in Server A and uploading the file in the same server) and worked fine. Here's the code of the succesful test (invoked as a component instead of a webservice):

<cfinvoke component="alta_ga" method="cargaAnuncio" destinoAnuncio="#form.destinoAnuncio#" PrefijoNvoNombre="#form.PrefijoNvoNombre#">

¿What could be wrong? There's a lack of documentation about this functionality. Adobe's user guide doesn't explain this functionality in depht. Ben Forta's books... same. Or I couldn't find the information. Thanks in advance.


Solution

  • When a form is posted to a CFML server, the posted file is saved in a temporary directory before any of your code runs. All <cffile action="upload"> does is to copy a file from that temporary directory to the location you want it to be. Your remote server ServerB has no idea about any file posted on ServerA, so <cffile action="upload"> will not help you.

    The action is misleading. It's not upload-ing anything. It's just copying from a predetermined temp directory. The web server handles the uploading before the CF server is even involved.

    You will likely need to <cffile action="upload"> on ServerA to a specific place, and then it needs to post that file to your web service on ServerB. Then ServerB should be able to use <cffile action="upload"> to transfer it from the upload temp directory to wherever you need it to be. That said I have never tried this when posting to a web service.

    Alternatively you could just post the file directly to ServerB in the first place, to save needing ServerA to be an intermediary. This might not be possible, of course.