I'm trying to post an XML file to a multipart HTML form, it's not working, and I can't figure out what the problem is. It appears that ColdFusion is just not transmitting the file. I've tried posting to the actual form I need to post to as well as a test page that dumps requests, and all that comes through are the form fields.
Here's the relevant part of my code:
<cfhttp url="#endPoint#" method="post" multipart="yes">
<cfhttpparam type="formField" name="file_name" value="test.xml">
<cfhttpparam type="formField" name="user_name" value="test">
<cfhttpparam type="formField" name="password" value="test">
<cfhttpparam type="file" name="test.xml" file="#localfile#">
</cfhttp>
I can confirm that endPoint points to a valid URL, the formField names/values are valid, and that test.xml does indeed exist at the location specified by localfile.
Suggestions? Any input would be appreciated!
Add'l info: I am on CF MX 6.1 if that makes a difference.
EDIT: After reviewing the input below, I did some more testing.
I can confirm that localfile is an absolute path (C:\path_to_my_files\test.xml).
I'm not sure what the target form is running on. I don't know for sure, but I don't think it's ColdFusion.
I built my own HTTP test page using GetHTTPRequestData() as mentioned below, and I think that works ok, though it looks a litle strange to me. Writing GetHTTPRequestData().content to a file lets me see what I'm trying to send. However, the final form still reports that I'm not including a file. Posttestserver.com also reports no file. I've included the result from both my page and the POST test server below.
My test page result:
-------------------------------7d0d117230764
Content-Disposition: form-data; name="file_name"
Content-Type: text/plain; charset=UTF-8
test.xml
-------------------------------7d0d117230764
Content-Disposition: form-data; name="user_name"
Content-Type: text/plain; charset=UTF-8
test
-------------------------------7d0d117230764
Content-Disposition: form-data; name="password"
Content-Type: text/plain; charset=UTF-8
test
-------------------------------7d0d117230764
Content-Disposition: form-data; name="test.xml"; filename="C:\my_files\test.xml"
Content-Type: text/xml
%3C%3Fxml%20version%3D%221%2E0%22%20encoding%3D%22UTF%2D8%22%20%3F%3E%3CjobFeed%3E%3Cjob%3E%3CjobId%3E1234%3C%2FjobId%3E%3CjobTitle%3ETest%20Job%3C%2FjobTitle%3E%3CjobCity%3ETest%20City%3C%2FjobCity%3E%3CjobState%3ETest%20State%3C%2FjobState%3E%3CjobDescription%3ETest%20Description%3C%2FjobDescription%3E%3CjobZip%3E12345%3C%2FjobZip%3E%3CjobUrl%3Ehttp%3A%2F%2Fwww%2Etest%2Ecom%3C%2FjobUrl%3E%3CJobType%3ETEC%3C%2FJobType%3E%3C%2Fjob%3E%3C%2FjobFeed%3E
-------------------------------7d0d117230764--
I've got no idea what this "-------------------------------7d0d117230764" business is.
Here's what I got from the test site:
Headers (Some may be inserted by server)
UNIQUE_ID = TlZTra3sqvkAAECsSBsAAAAL
HTTP_HOST = www.posttestserver.com
HTTP_CONNECTION = close
HTTP_USER_AGENT = ColdFusion
HTTP_ACCEPT_ENCODING = deflate, gzip, x-gzip, compress, x-compress
CONTENT_TYPE = multipart/form-data; boundary=-----------------------------7d0d117230764
CONTENT_LENGTH = 1159
GATEWAY_INTERFACE = CGI/1.1
REQUEST_METHOD = POST
QUERY_STRING =
REQUEST_URI = /post.php
REQUEST_TIME = 1314280365
Post Params:
key: 'file_name' value: 'test.xml'
key: 'user_name' value: 'test'
key: 'password' value: 'test'
== Begin post body ==
== End post body ==
Here it appears I've transmitted no file.
I'm still looking at it, but I'm not seeing the problem. Ideas?
When you specify a type of file, then the file data is sent in the post body, not in a form field name that you can reference. If you check the LiveDocs on CFHTTPPARAM it states for the type="file" attribute:
The absolute path to the file that is sent in the request body.
So as Leigh stated, on your receiving page, you need to use GetHttpRequestData, something like this:
<cfset objRequest = GetHttpRequestData() />
<cfset object = objRequest.Content() />
If the endPoint is a CF page, then I am wondering if something else may be going on. The data is sent in the request body, yes. But with CF pages, it should still parse the information and create a form field for that file. Same as with a regular form upload. In this case the field name would be form["test.xml"]. Could that be part of the issue?
CFDUMP results under MX6.1 and CF9
FIELDNAMES FILE_NAME,USER_NAME,PASSWORD,TEXT.XML
FILE_NAME test.xml
PASSWORD test
TEXT.XML C:\CFusionMX\...\temp\wwwroot-tmp\neotmp6275345679234991.tmp
USER_NAME test
Note: One difference under CF9 was that getHttpRequestData().content is empty. Whereas under MX6 it is still populated. Seems like 6.1 preserves a copy of the data (after processing it) but CF9 does not. Not sure why.
Related
On this question I asked about what the structure of the email should be. This question is about how to use cfmail (and cfmailpart, cfmailparam, etc.) to produce the correct structure.
The desired structure is:
multipart/mixed
multipart/alternative
text/plain
text/html
image/jpeg
application/pdf
The code I've got currently:
<cfmail from='"No Reply" <noreply#example.com>' subject="Test 123" to="my_outlook_address#example.com,my_gmail_address#gmail.com">
<!--- Some code to get a query of attachment content here... --->
<cfloop query="qAttachments">
<!---
Some code to get the attachment file data here and put it in a variable named `myfile`...
myfile structure:
{
fileName: <string>,
fileContent: <base64 encoded file content>,
mimeType: <image/jpeg for the one, application/pdf for the other>
}
--->
<cfmailparam disposition="attachment" contentID="#myfile.fileName#" content="#myfile.fileContent#" file="#myfile.fileName#" type="#myfile.mimeType#" />
</cfloop>
<cfmailpart type="plain">
My plain text
</cfmailpart>
<cfmailpart type="html">
<strong>My fancypants text</strong>
</cfmailpart>
</cfmail>
However, this produces this structure:
multipart/mixed
multipart/alternative
text/plain
multipart/related
text/html
image/jpeg
application/pdf
I've tried code like this:
<cfmail from='"No Reply" <noreply#example.com>' subject="Test 123" to="my_outlook_address#example.com,my_gmail_address#gmail.com">
<!--- Some code to get a query of attachment content here... --->
<cfloop query="qAttachments">
<cfmailparam disposition="attachment" contentID="#myfile.fileName#" content="#myfile.fileContent#" file="#myfile.fileName#" type="#myfile.mimeType#" />
</cfloop>
<cfmailpart type="multipart/alternative">
<cfmailpart type="plain">
My plain text
</cfmailpart>
<cfmailpart type="html">
<strong>My fancypants text</strong>
</cfmailpart>
</cfmailpart>
</cfmail>
But then it just goes to the undelivered email list in cfadmin.
With both versions of the code I tried for values of the type attribute on the cfmail tag itself:
plain
html
multipart/mixed
multipart/alternative
to no avail.
How do I achieve the desired MIME structure in ColdFusion?
My approach I landed on may not be ideal, but it works in all 3 mail clients I was targeting. What I ended up doing was this:
for any image attachments, I would include a contentID attribute on the cfmailparam tag and include an <img src="cid:..."> with the contentID value
for all other attachments, I omit the contentID attribute on the cfmailparam tag
This has the end result that all images are presented inline in the message body, and all other files are displayed as regular file attachments.
Based on the discussion by who I assume is a developer on the CF team here https://tracker.adobe.com/#/view/CF-4166939 I'm under the impression that the MIME header structure is controlled by ColdFusion and isn't directly manageable by ColdFusion developers. Unfortunate, but at least I have something of a workaround. Hopefully this will help someone.
UPDATED WITH WORKING SOLUTION
I'm trying to integrate the DocuSign API using ColdFusion and keep running into an issue. I am able to authenticate successfully and retrieve the base URL. However, when trying to create the envelope with a single recipient and document, I get an error stating that the "boundary terminator" is not found in the request (when it clearly is).
I know this questions is similar to another post here but that was from a while ago and was never completely answered.
I first read in the PDF document:
<cffile action="READBINARY" file="Agreement.pdf" variable="docData">
<cfset docData = BinaryEncode(docData,"Base64")>
I then create the envelope definition in XML using the element to include the encoded binary PDF data:
<cfset envelope = "<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
<status>Sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<recipientId>1</recipientId>
<name>eCS Buyer</name>
<email>XXX#XXXX.com</email>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>3</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>#docData#</documentBase64>
</document>
</documents>
</envelopeDefinition>">
Lastly, I POST the information:
<cfhttp url="#baseURL#/envelopes" method="POST" resolveurl="Yes" throwonerror="No">
<cfhttpparam name="X-DocuSign-Authentication" type="HEADER" value="<DocuSignCredentials><Username>#userName#</Username><Password>#password#</Password><IntegratorKey>#integratorKey#</IntegratorKey></DocuSignCredentials>">
<cfhttpparam name="Content-Type" type="HEADER" value="application/xml">
<cfhttpparam name="Accept" type="HEADER" value="application/xml">
<cfhttpparam name="Content-Length" type="HEADER" value="#Len(envelope)#">
<cfhttpparam name="request_body" type="BODY" value="#envelope#">
</cfhttp>
I tried changing the TYPE attribute for the request body to XML and FORMFIELD but is still doesn't work. I even tried changing the envelope to JSON format to no avail.
The error that is generated is:
<errorCode>INVALID_REQUEST_BODY</errorCode><message>The request body is missing or improperly formatted. The XML request does not match the expected format. </message></errorDetails>
I have been struggling with this for weeks. Any guidance would be GREATLY appreciated.
Most likely an issue with extra CRLF (i.e., extra line breaks). See the answer in this other forum post for an example of what the full request structure should look like: Docusign : Unable to create envelope from document in restapi v2.
UPDATE #1
Looks like your XML request body is missing information about the Document. Try adding a documents element as a child element of envelopeDefinition (i.e., as a peer element to recipients):
<envelopeDefinition xmlns=""http://www.docusign.com/restapi"">
...
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
</document>
</documents>
...
</envelopeDefinition>
Also, make sure the document bytes that your sending in the subsequent part of the request are not encoded.
UPDATE #2
I don't know much about ColdFusion, but this line of your code makes it look like you're (base64) encoding the byte stream that you're including in the Request:
<cfset docData = BinaryEncode(docData,"Base64")>
This could be causing your latest issue, as I don't believe DocuSign will accept an encoded byte stream when it's included in the manner you're currently utilizing.
If you must base64-encode the byte stream, you could add a documentBase64 property under the document element to contain the base64-encoded byte stream. (See page 104 of the DocuSign REST API Guide -- http://www.docusign.com/sites/default/files/REST_API_Guide_v2.pdf.) If you utilized this approach, your request would no longer need to be a 'multipart' request, since the document bytes would be included in the XML portion of the Request Body (not in a subsequent/separate part). Here's an example of what the Request would look like, if the base64-encoded byte stream was included within the documentBase64 element:
POST /restapi/v2/accounts/ACCOUNT_NUMBER/envelopes HTTP/1.1
Host: demo.docusign.net
X-DocuSign-Authentication: {"Username":"SENDER_EMAIL_ADDRESS","Password":"PASSWORD","IntegratorKey":"INT_KEY"}
Content-Type: application/xml
<envelopeDefinition xmlns="http://www.docusign.com/restapi">
<accountId>ACCOUNT_ID</accountId>
<status>sent</status>
<emailSubject>eSignature request</emailSubject>
<emailBlurb>Please sign the document</emailBlurb>
<recipients>
<signers>
<signer>
<email>johnsEmail#outlook.com</email>
<name>John Doe</name>
<recipientId>1</recipientId>
<routingOrder>1</routingOrder>
<tabs>
<signHereTabs>
<signHere>
<documentId>1</documentId>
<pageNumber>1</pageNumber>
<xPosition>10</xPosition>
<yPosition>100</yPosition>
</signHere>
</signHereTabs>
</tabs>
</signer>
</signers>
</recipients>
<documents>
<document>
<name>Agreement.pdf</name>
<documentId>1</documentId>
<fileExtension>pdf</fileExtension>
<documentBase64>BASE64-ENCODED-BYTE-STREAM</documentBase64>
</document>
</documents>
</envelopeDefinition>
Since the document bytes are included within the XML portion of the request, the request no longer needs to be multi-part -- simply pass the XML Request body as I've shown above, and that's it.
The error is most likely due to the extra CRLF you have after the document bytes and before your closing boundary --MYBOUNDARY--. You have this:
#docData#
--MYBOUNDARY--
Try changing that to this without that extra CRLF:
#docData#
--MYBOUNDARY--
For reference you can check out the DocuSign API Walkthrough for sending a signature request on a document. Each of the different language versions shows you how the outgoing request body should be formatted.
I have a question regarding sending a Web API call to sendgrid:
The following documentation is used to retrieve advanced stats:
http://sendgrid.com/docs/API_Reference/Web_API/Statistics/statistics_advanced.html
In the "Call" section, the following has been mentioned:
POST https://api.sendgrid.com/api/stats.getAdvanced.json
POST Data api_user=your_sendgrid_username&api_key=your_sendgrid_password&start_date=2013-01-01&end_date=2013-01-02&data_type=global
I understand that I need to use cfhttp for the Web API call and I should be
mentioning "https://api.sendgrid.com/api/stats.getAdvanced.json" in the url parameter
of the cfhttp tag.
Where do I need to mention api_user and api_key portion? I understand that I will have
to mention my sendgrid's account username and password here.
For Explanation Purpose let's consider the following dummy values for:
api_user = stack
api_key = 123456
Please let me know. I am trying to send an API call an get the data back in JSON format.
Thanks
ATTEMPT #1
I am using the following code:
<cfhttp url="https://api.sendgrid.com/api/stats.getAdvanced.json" method="POST" result="returnStruct">
<cfhttpparam name="api_user" value="stack" type="formfield">
<cfhttpparam name="api_key" value="123456" type="formfield">
<!--- <cfhttpparam name="days" value="5" type="formfield"> --->
<cfhttpparam name="start_date" value="2013-12-06" type="formfield">
<!--- <cfhttpparam name="end_date" value="2013-12-09" type="formfield"> --->
</cfhttp>
<cfdump var="#returnStruct#">
I am getting the following error in the form of Structure. Am I doing something wrong above? Please check my code below.
Charset [empty string]
ErrorDetail [empty string]
Filecontent {"error": "error in data_type: data_type is required"}
Header HTTP/1.1 400 Bad Request Content-Type: text/html Connection: close Date: Tue, 10 Dec 2013 06:21:19 GMT Server: nginx/1.4.2
Mimetype text/html
Responseheader
struct
Connection close
Content-Type text/html
Date Tue, 10 Dec 2013 06:21:19 GMT
Explanation Bad Request
Http_Version HTTP/1.1
Server nginx/1.4.2
Status_Code 400
Statuscode 400 Bad Request
Text YES
I am wondering, which data_type it is referring to, as the documentation doesn't talks about it.
Typically, you would use <cfhttpparam> for each of the keys:
<cfhttp url="https://api.sendgrid.com/api/stats.getAdvanced.json" method="POST">
<cfhttpparam name="api_user" value="some_username_goes_here" type="formfield">
<cfhttpparam name="api_key" value="some_api_key_goes_here" type="formfield">
...more params...
</cfhttp>
I have a twitter application which sends tweets automatically for uses of our blog application whenever they post a new blog item.
This application is now returning an error
HTTP/1.1 401 Unauthorized Content-Type: application/json; charset=utf-8 Date: Mon, 12 Nov 2012 22:05:27 UTC Server: tfe
{"errors":[{"message":"Could not authenticate you","code":32}]}
My coldfusion code is as follows for posting the tweet:
<cfset var tweetURL = "https://api.twitter.com/1.1/statuses/update.json">
<cfhttp url="#tweetURL#" method="post" result="result">
<cfhttpparam type="header" name="Authorization" value="#oauth.header#" encoded="no">
<cfhttpparam type="formfield" name="status" value="#tweet#" encoded="no">
</cfhttp>
I have dumped out all the oauth header values, they are all as they should be, they are not returning any errors at all. its only the status update that is returning the unauthorized error.
What other things do I need to check? I thought my app may have been blocked or something but its all up and working. I've tested the user accounts they have authorized the app.
I worked it out. I was to busy validating the input of the header and auth tokens etc that I overlooked the status. It wasn't urlencoded. although this apparently worked in the old version. it didn't pass for the new.
We are trying to interact with a RESTful web service that expects a file.
I set the name of the field to data (as required by the API) and then specify the file as an absolute path. When the file makes it to the server, the filename in the HTTP transaction is the complete absolute path.
This causes a problem with the API as the full path is then recorded as the "FileName".
How do I get ColdFusion to report only the file name rather than the full path?
We are using ColdFusion 9.
Here is the CFML:
<cfhttp url="http://server/testcode"
port="9876"
method="post"
result="Content">
<cfhttpparam type="file"
name="data"
file="c:\temp\testfile.txt">
</cfhttp>
Here are some examples of the HTTP interactions with different browsers:
CFHTTP 9
-------------------------------7d0d117230764
Content-Disposition: form-data; name="data"; filename="c:\temp\testfile.txt"
Content-Type: text/plain
This is the text, really long, well, not really.
-------------------------------7d0d117230764--
IE8
-----------------------------7db370d80e0a
Content-Disposition: form-data; name="FileField"; filename="C:\temp\testfile.txt"
Content-Type: text/plain
This is the text, really long, well, not really.
-----------------------------7db370d80e0a--
Chrome 13
------WebKitFormBoundaryDnpFVJwCsZkzTGDc
Content-Disposition: form-data; name="FileField"; filename="testfile.txt"
Content-Type: text/plain
This is the text, really long, well, not really.
Firefox 6
-----------------------------22798303036224
Content-Disposition: form-data; name="FileField"; filename="testfile.txt"
Content-Type: text/plain
This is the text, really long, well, not really.
-----------------------------22798303036224--
Apparently IE8 and CFHTTP both do the same thing (add "c:\temp" to the file name). I'm not sure what the spec for HTTP is, but it would be nice if there was a way to get CFHTTP to leave the path off.
Is there any way to do this?
I ran into a problem similar to yours, once. I didn't care about excluding the path, but I wanted to send a different filename than the name of the file on my server's filesystem. I could not find a way to do it using CF tags at all, but I was able to get it to work by dropping into Java. I used org.apache.commons.httpclient, which ships with CF9 IIRC. It goes something like this (pardon any typos, I'm transposing from more complicated code):
oach = 'org.apache.commons.httpclient';
oachmm = '#oach#.methods.multipart';
method = createObject('java', '#oach#.methods.PostMethod').init(post_uri);
filePart = createObject('java', '#oachmm#.FilePart').init(
'fieldname',
'filename',
createObject('java', 'java.io.File').init('filepath')
);
method.setRequestEntity(
createObject('java', '#oachmm#.MultipartRequestEntity').init(
[ filePart ],
method.getParams()
)
);
status = createObject('java', '#oach#.HttpClient').init().executeMethod(method);
method.releaseConnection();
I see that the content type is text/plain so first I think that you need to add the multipart property on the CFHTTP
<cfhttp url="http://server/testcode"
port="9876"
method="post"
result="Content"
multipart = "yes">
<cfhttpparam type="file"
name="data"
file="c:\temp\testfile.txt">
</cfhttp>
Could solve your issue.
The only difference I see between all of the posts is that CF is sending name="data" while everything else is sending name="FileField". If the other browser submissions are correct, then I would change your cfhttpparam:
<cfhttpparam type="file"
name="FileField"
file="c:\temp\testfile.txt">
or even try sending an additional FileName parameter:
<cfhttpparam type="file"
name="data"
file="c:\temp\testfile.txt" />
<cfhttpparam type="formField"
name="FileName"
value="testfile.txt" />
So I was able to get access to the API and made it work. Here is the code for this specific part (as I assume that you were able to login and get a document guid).
<!--- upload a document --->
<cfhttp method="post" url="<path to watchdox api upload>/#local.guid#/upload">
<cfhttpparam type="header" name="Content-type" value="multipart/form-data">
<cfhttpparam type="header" name="x-wdox-version" value="1.0">
<cfhttpparam type="header" name="x-wdox-ssid" value="#local.xwdoxssid#" >
<cfhttpparam type="formfield" name="filename" value="testfile.txt" >
<cfhttpparam type="file" file="c:\temp\testfile.txt" name="data" >
</cfhttp>
Hope it will help.