I am trying to perform a CFHTTP call using Lucee 4.5. Test code on my main workstation is ok (running CF 10), but when copied exactly to a laptop with Lucee if fails with 400 error invalid headers sent. See below
#XML Being Passed
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<SOAP-ENV:Body>
<m:Authenticate xmlns:m="http://foo.com/2005/">
<m:userName>xxxxx</m:userName>
<m:password>xxxxx</m:password>
</m:Authenticate>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
#Partial Codebase; 'variable' is XML posted above
<cfhttp url="http://xxxxxxx?WSDL" method="post" result="theCFHTTP" compression="false">
<cfhttpparam type="HEADER" name="Content-Type" value="text/xml; charset=utf-8">
<cfhttpparam type="HEADER" name="Accept" value="application/soap+xml, application/dime, multipart/related, text/*">
<cfhttpparam type="HEADER" name="User-Agent" value="Axis/1.1">
<cfhttpparam type="HEADER" name="Cache-Control" value="no-cache">
<cfhttpparam type="HEADER" name="Pragma" value="no-cache">
<cfhttpparam type="HEADER" name="SOAPAction" value="http://foo.com/2005/Authenticate">
<cfhttpparam type="HEADER" name="Content-Length" value="#len(soap)#">
<cfhttpparam type="xml" name="body" value="#soap#">
</cfhttp>
I am very new to Lucee and never used Railo so if there are unique charsets or other configuration options that need to be done I'd appreciate the help.
Edit: Further tests have determined that I cannot CFHTTP to any page outside of the laptop itself. All external URLs give a 400 bad header message.
I also added compression=false so that Lucee would not auto send GZip content to the request url.
My working machine's return headers:
Charset: utf-8
Header: HTTP/1.1 200 OK Cache-Control: private, max-age=0 Content-Type: text/xml; charset=utf-8 Server: Microsoft-IIS/8.0 X-AspNet-Version: 4.0.30319 X-Powered-By: ASP.NET Date: Wed, 25 Mar 2015 14:58:03 GMT Connection: close Content-Length: 603
Mimetype: text/xml
The failing machine's return headers:
Charset: us-ascii
Header: HTTP/1.1 400 Bad Request Content-Type: text/html; charset=us-ascii Server: Microsoft-HTTPAPI/2.0 Date: Wed, 25 Mar 2015 15:06:18 GMT Connection: close Content-Length: 339
Mimetype: text/html
MAY 19 EDIT:
I tested each of the following adjustments separately within the CFHTTP call based on Fabio's response:
I removed the Content-Type header param, or
Changed the body param from 'xml' to 'body'
Neither worked, though my error message has changed to 400 Bad Request. A dump of the CFHTTP call says I am sending invalid XML though independent checks verify it is, in fact, valid. It's failing at the token authentication call.
I had the same problem today. Finally, I got it!
I sniffed network traffic using tcpdump and It looked like our request to IIS7 contained the Content-Type header twice, thus resulting in the ugly
Bad Request - Invalid Header Name error
The problem is in the body parameter:
<cfhttpparam type="xml" name="body" value="#soap#">
Lucee sets the Content-Type header accordingly, to text/xml; utf-8... then sets it once again based on your other parameter:
<cfhttpparam type="HEADER" name="Content-Type" value="text/xml; charset=utf-8">
You have two choices:
leave type="xml" to your cfhttpparam tag, and remove the explicit MIME+charset param
change type="xml" to type="body" and manually set all of your headers
Related
I am attempting to run a simple REST api with ColdFusion and receiving same error regardless of attempt.
The call works fine in Postman with the 4 params. But cant recreate in ColdFusion CFHTTP.
<cfhttp url="https://api.sandbox.scoutrfp.com/v3/contracts" method="GET" result="ITEM_INFO">
<cfhttpparam type="header" name="X-Api-Key" value="#variables.API_KEY#">
<cfhttpparam type="header" name="X-User-Token" value="#variables.USER_TOKEN#">
<cfhttpparam type="header" name="Content-Type" value="application/vnd.api+json">
<cfhttpparam type="header" name="X-User-Email" value="#variables.USER_EMAIL#">
</cfhttp>
I have replaced the header with type cgi as
<cfhttpparam type="CGI" encoded="false" name="Content_Type" value="application/vnd.api+json">
I have added all temp headers that postman sends.
Always same error: Missing or incorrect Content-Type header for JSON:API: Expected request to include 'Content-Type: application/vnd.api+json
Seems CFHTTP tag not properly sending value "application/vnd.api+json" - perhaps encoding it incorrectly in some fashion? Is there another means to send this Content-Type via CFHTTP to get a response?
The content-type application/vnd.api+json might be too new for ColdFusion.
Another way to send the content-type header via HTTP is to use Curl
(The intention in the code is to save the result in the current directory. That is, the directory containing this CFM file)
<!--- Use your own path to the Curl executable --->
<cfexecute name = "C:\bin\curl-7.35.0-win64\bin\curl.exe"
arguments = ' -H "X-Api-Key:#variables.API_KEY#" -H "X-User-Token:#variables.USER_TOKEN#" -H "Content-Type:application/vnd.api+json" -H "X-User-Email:#variables.USER_EMAIL#" https://api.sandbox.scoutrfp.com/v3/contracts '
outputfile="#expandPath('.')#\ITEM_INFO.html" />
using an extra header for X-HTTP-Method-Override = GET after changing method to POST worked. The Curl solution also worked with an inserted after the cfexecute and before attempting to read the newly created file written with the returned api content.
<cfhttp url="https://#variables.ENVIRONMENT#/v3/contracts" method="POST" result="ITEM_INFO">
<cfhttpparam type="header" name="X-Api-Key" value="#variables.API_KEY#">
<cfhttpparam type="header" name="X-User-Token" value="#variables.USER_TOKEN#">
<cfhttpparam type="header" name="Content-Type" value="application/vnd.api+json">
<cfhttpparam type="header" name="X-User-Email" value="#variables.USER_EMAIL#">
<cfhttpparam type="header" name="X-HTTP-Method-Override" value="GET">
</cfhttp>
Is it possible to redirect an incorrect subdomain (A non-existant subdomain) to a certain page (Custom error page)?
EDIT: Using a web.config file
For example, if I typed http://foo.squishling.co.uk/ it would redirect to something like http://squishling.co.uk/errors/incorrect_subdomain.html/, as http://foo.squishling.co.uk/ isn't a correct subdomain.
I haven't seen any code that does this, so is it possible?
EDIT: If it isn't possible, please say so
Thanks in advance,
~ Squishling
EDIT: If this is possible, a possible way of doing it would be when the server recieves a request for the incorrect subdomain, just trick the request into requesting an error page
Yes, it's possible. Here's how with IIS 10 + UrlRewrite 2.1.
For example's purposes let's assume I have:
A valid domain/port good.localhost:81
my custom error file # /error.txt
Step 1: Set up site bindings to accept requests for sub domains
IIS manager -> web site context menu -> "Edit Bindings.."
Edit accepted host name to accept *.<yourDomain>. For the example case:
Detailed steps can be found from documentation page "Wildcard Host Header Support".
Now site should respond to both http://good.localhost:81 as well as http://bad.localhost:81.
Step2: install Url rewrite module
You can find URL rewrite module installer from here:
https://www.iis.net/downloads/microsoft/url-rewrite
Step3: configure redirect rule
While you could use IIS MAnager's GUI for this, you could as well just handwrite something like this to your web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="DirectBadSubdomainsRule" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^good\.localhost:81" negate="true" />
</conditions>
<action type="Redirect" url="http://good.localhost:81/error.txt" redirectType="Temporary" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
You can use the power of regex to determine which subdomains are valid and which ones are not. Also you can decide exactly which redirection code you want. The example above uses Temporary redirect (HTTP307).
There's a lot of documentation in here: https://www.iis.net/downloads/microsoft/url-rewrite
Testing
Non-good domain should now return redirection response:
http://bad.localhost:81/correct.txt -> HTTP307
http://good.localhost:81/error.txt -> HTTP200
Sure you can.
Here's a minimal nginx configuration doing this:
server {
listen 80 default_server;
server_name _;
location / {
rewrite ^.*$ http://squishling.co.uk/errors/incorrect_subdomain.html redirect;
}
}
server {
listen 80;
server_name squishling.co.uk;
location / {
echo some page;
}
location /errors/incorrect_subdomain.html {
echo incorrect subdomain error;
}
}
This is how to run it:
mkdir conf.d
put the config file above into conf.d/main.conf
docker run -p80:80 -v ~/work/test/subreq/conf.d:/etc/nginx/conf.d openresty/openresty:alpine
testing
squishling.co.uk and foo.squishling.co.uk are overridden in my /etc/hosts so they direct to my localhost
curl -D - http://squishling.co.uk
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Tue, 06 Feb 2018 18:49:25 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive
some page
Now trying the wrong domain
curl -D - http://foo.squishling.co.uk
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.13.6.1
Date: Tue, 06 Feb 2018 18:49:34 GMT
Content-Type: text/html
Content-Length: 167
Connection: keep-alive
Location: http://squishling.co.uk/errors/incorrect_subdomain.html
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
<center><h1>302 Found</h1></center>
<hr><center>openresty/1.13.6.1</center>
</body>
</html>
Or the same following the redirection:
curl -L -D - http://foo.squishling.co.uk
HTTP/1.1 302 Moved Temporarily
Server: openresty/1.13.6.1
Date: Tue, 06 Feb 2018 18:50:03 GMT
Content-Type: text/html
Content-Length: 167
Connection: keep-alive
Location: http://squishling.co.uk/errors/incorrect_subdomain.html
HTTP/1.1 200 OK
Server: openresty/1.13.6.1
Date: Tue, 06 Feb 2018 18:50:03 GMT
Content-Type: text/html
Transfer-Encoding: chunked
Connection: keep-alive
incorrect subdomain error
So the main idea is that you define the default server configuration that would intercept all the domains besides those having individual configurations. The same can be accomplished in other web servers too
Try this one. Reference from https://stackoverflow.com/a/10662732/7877099
<configuration>
<system.webServer>
<httpRedirect enabled="true" destination="http://squishling.co.uk/errors/" exactDestination="true" httpResponseStatus="Permanent" />
</system.webServer>
<location path="incorrect_subdomain.html">
<system.webServer>
<httpRedirect enabled="false" />
</system.webServer>
</location>
</configuration>
thanks to all for reading about this.
I'm testing Dynamics CRM 2011 Endpoint with SOAP, and after configuring a test suite with SOAPUi the response from the request is coming back as web page that reads: "Script is disabled. Click Submit to continue."
It' seems that both authentication and request is correct and I tried to change different parameters in SOAPUi following experiences from other users but anything had worked for me.
It's a SOAPUi misconfiguration? Or it came from the service Endpoint?
I've also checked this article from Technet: http://social.technet.microsoft.com/wiki/contents/articles/1425.ad-fs-2-0-script-is-disabled-click-submit-to-continue.aspx
I'm calling a Dynamics CRM 2011 On Premise SOAP Endpoint
SOAPUi Test Request
Headers:
SOAPAction http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Retrieve
Accept application/xml, text/xml, */*
Content-Type text/xml; charset=utf-8
Request URL: http://myserver/XRMServices/2011/Organization.svc/web
Authentication: NTLM (with user, password and domain)
Request:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ser="http://schemas.microsoft.com/xrm/2011/Contracts/Services" xmlns:con="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:arr="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<soap:Header/>
<soap:Body>
<ser:entityName>contact</ser:entityName>
<ser:id>91A6E0D1-1182-E511-B589-5EF3FC563A99</ser:id>
<ser:columnSet>
<con:AllColumns>false</con:AllColumns>
<con:Columns>
<arr:string>fullname</arr:string>
</con:Columns>
</ser:columnSet>
</ser:Retrieve>
</soap:Body>
</soap:Envelope>
Response: (I've cleared some private information)
<html>
<head>
<title>Working...</title>
</head>
<body>
<form method="POST" name="hiddenform" action="http://myserver:444/">
<input type="hidden" name="wa" value="wsignin1.0"/>
<input type="hidden" name="wresult" value="*here was my security token*"/>
<input type="hidden" name="wctx" value="rm=1&id=40167dd3-3ac9-4961-a476-3b7ada5a6395&ru=%2fmyorganization%2fXRMServices%2f2011%2fOrganization.svc%2fweb"/>
<noscript>
<p>Script is disabled. Click Submit to continue.</p>
<input type="submit" value="Submit"/>
</noscript>
</form>
<script language="javascript">window.setTimeout('document.forms[0].submit()', 0);</script>
</body>
</html>
I am working with an API that has two different URLs for specific types of functions. The first, is a transactional API that supports either JSON or SOAP requests. I have called all of the functions I need within this API using exclusively JSON calls and everything appears to be working perfectly fine.
The second is a reporting API used to locate and/or download reports. This API works exclusively with SOAP. I have not been able to get any function in this API working properly. I have attempted to contact the company's support group, but they do not have anybody who can assist me with API calls in ColdFusion. I have attempted two different ways to interface with this API and get access to the functions and have come up empty. Below are my examples and as much information as I can provide; our service provider's API and associated documentation are confidental, but I can answer some questions related to specific things that have to do with my code.
Way 1: Creating a webservice object.
The first way I tried to create this SOAP call was through a webservice object. Using the metadata exchange point URL, I passed it into the createObject function like this:
<cfset argStruct = structNew() />
<cfset argStruct['username'] = 'myusername' />
<cfset argStruct['password'] = 'mypassword' />
<cfset testSvc = createObject('webservice','https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex',argStruct) />
When I run this code, I get the following error message:
Cannot generate stub objects for web service invocation. Name: https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex. WSDL: https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex. javax.wsdl.WSDLException: WSDLException (at /wsdl:definitions/wsdl:import): faultCode=OTHER_ERROR: Unable to resolve imported document at 'https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex?wsdl=wsdl1', relative to 'brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/': java.io.IOException: Server returned HTTP response code: 401 for URL: https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex?wsdl=wsdl1
Since 401 errors are typically bad authorizations, I double-checked the address by calling the URL directly in the browser, where I was prompted with a UN/PW. I entered in my values, and was allowed to access the URL, recieving this XML in return:
<?xml version="1.0" encoding="utf-8"?>
<wsdl:definitions name="ReportingAPI" targetNamespace="https://https://brandnameapi.serviceprovider.com/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsa10="http://www.w3.org/2005/08/addressing" xmlns:wsx="http://schemas.xmlsoap.org/ws/2004/09/mex" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:wsap="http://schemas.xmlsoap.org/ws/2004/08/addressing/policy" xmlns:msc="http://schemas.microsoft.com/ws/2005/12/wsdl/contract" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsam="http://www.w3.org/2007/05/addressing/metadata" xmlns:wsaw="http://www.w3.org/2006/05/addressing/wsdl" xmlns:tns="https://https://brandnameapi.serviceprovider.com" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:i0="https://https://brandnameapi.serviceprovider.com/ReportingAPI/soapBinding" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">
<wsdl:import namespace="https://https://brandnameapi.serviceprovider.com/ReportingAPI/soapBinding" location="https://https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex?wsdl=wsdl1"/>
<wsdl:types/>
<wsdl:service name="ReportingAPI">
<wsdl:port name="BasicHttpBinding_IReportingAPI" binding="i0:BasicHttpBinding_IReportingAPI">
<soap:address location="https://https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/soap"/>
</wsdl:port>
</wsdl:service>
This is about as far as I've gotten. When I call the URL with my browser and pass the authentication information, I'm allowed to access the XML. When I try to do so with ColdFusion, I get 401 errors.
Way 2: cfhttp request calls
When I switched to using cfhttp, I seemed to get a little further. When I use this:
<cfhttp url="https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/mex"
username="myusername" password="mypassword" method="get" result="httpResponse"
timeout="300">
</cfhttp>
httpResponse return appropriate page information, and httpResponse.filecontent returns the same XML I recieved when I called it directly in my browser.
Going one step further, I took the SOAP URL and attempted to call a function in the API that returns a list of available report files. I used the same known-working process I used for all of my JSON calls in the transaction API:
<cfhttp url="https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/soap/queryAvailableReportFiles"
username="myusername" password="mypassword" method="post"
result="httpResponse" timeout="300">
<cfhttpparam type="formfield" name="typeOfReport" value="DailyCSVFile" />
</cfhttp>
When I run this code, I get a status code of 415 and an error of, 'Cannot process the message because the content type 'application/x-www-form-urlencoded' was not the expected type 'multipart/related; type="application/xop+xml"'
When I add this line between my cfhttps:
<cfhttpparam type="header" name="Content-Type" value='multipart/related; type="application/xop+xml"' />
I get the same error as directly above, but the status code changes to 400. I have not included everything I've tried to do, only where I'm at right now. I will answer as many questions as I can and will reperform steps as directed to find a solution to this problem.
Update: As requested, I have changed the cfhttp call to attempt to pass XML instead of a form field. My XML code is ripped directly from the API documentation that has an example of a raw data for a request from the API for a different function:
<cfsavecontent variable="soapBody">
<cfoutput>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<queryAvailableReportFiles
xmlns="https://brandnameapi.sandbox.serviceprovider.com/contract">
<fileName>DailyCSVFile</fileName>
</queryAvailableReportFiles>
</s:Body>
</s:Envelope>
</cfoutput>
</cfsavecontent>
<cfhttp url="https://prismproapi.sandbox.koretelematics.com/4/ReportingAPI.svc/soap/queryAvailableReportFiles" username="vfapi" password="bPzqQyK3" method="post" result="httpResponse" timeout="300">
<cfhttpparam type="xml" value="#trim(soapBody)#" />
</cfhttp>
To be fair, I have no idea if I'm doing that right. The error message that returns from it is, "The message with To https://prismproapi.sandbox.koretelematics.com/4/ReportingAPI.svc/soap/queryAvailableReportFiles cannot be processed at the receiver, due to an AddressFilter mismatch at the EndpointDispatcher. Check that the sender and receiver's EndpointAddresses agree." I also get a 500 error.
Here is an example of how I typically compose and execute my SOAP requests. Note that you will need to modify the SOAP body to fit your API's needs. Hopefully this will help lead you in the right direction.
By the way, Ben Nadel has an excellent right up on Making SOAP Web Service Requests With ColdFusion And CFHTTP
Here is my sample code:
<!--- Compose SOAP message to send to Web Service --->
<cfsavecontent variable="soapRequest">
<?xml version="1.0" encoding="UTF-8" ?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:example="http://www.domain.com/soap/example/">
<soapenv:Header/>
<soapenv:Body>
<example:ReportAPI>
<typeOfReport>DailyCSVFile</typeOfReport>
</example:ReportAPI>
</soapenv:Body>
</soapenv:Envelope>
</cfsavecontent>
<!--- Send SOAP request to the Web Service --->
<cfhttp url="https://brandnameapi.sandbox.serviceprovider.com/vernum/ReportingAPI.svc/soap/queryAvailableReportFiles" username="myusername" password="mypassword" method="post" result="httpResponse" timeout="300">
<cfhttpparam type="header" name="content-type" value="text/xml" />
<cfhttpparam type="header" name="content-length" value="#Len(Trim(soapRequest))#" />
<cfhttpparam type="header" name="charset" value="utf-8" />
<cfhttpparam type="xml" name="message" value="#Trim(soapRequest)#" />
</cfhttp>
There was a problem with their API. No code change would have addressed this issue.
I am trying to send the SearchRequest to find the stuff I need in the mailbox. However, I keep on getting the unknown Document error.
POST /service/soap HTTP/1.1
SOAPAction: ""
Content-Type: text/xml;charset="utf-8"
Accept: text/xml
Host: 192.168.138.133
Content-Length: 514
Expect: 100-continue
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<authToken>%token acquired from AuthRequest%</authToken>
<context xmlns="urn:zimbra" />
</soap:Header>
<soap:Body>
<SearchRequest xlmns="urn:zimbraMail">
<query>is:unread</query>
</SearchRequest>
</soap:Body>
</soap:Envelope>
It seems to me, that I have the wrong xmlns specified, but the zimbra soap api reference says that the namespace should be zimbraMail. Still I keep on getting the error.
Shouldn't there be a session somewhere in the headers ? (inside context)
http://dropcanvas.com/521xc/91
Try
<soap:Header>
<context xmlns="urn:zimbra" >
<authToken>%token acquired from AuthRequest%</authToken>
</context>
</soap:Header>