Webservice denies access on SOAP request Node.js - node.js

I'm attempting to get a SOAP response from a web service without using any libraries in Node, but I'm getting nowhere with the code I have. The WSDL for the service can be found here. I've tested the request in SoapUI, and with curl in a batch file. The JavaScript:
const http = require('http')
const fs = require('fs')
const xml = fs.readFileSync('latlonzipcode.xml','utf-8')
const options = {
hostname : 'graphical.weather.gov',
path : '/xml/SOAP_server/ndfdXMLserver.php',
method : 'POST',
headers : {
'Content-Type' : 'text/xml;charset=utf-8',
'soapAction' : 'https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl#LatLonListZipCode'
}
}
var obj = http.request(options,(resp)=>{
let data = ''
console.log(resp.statusCode)
console.log(resp.headers)
resp.on('data',(chunk)=>{
data += chunk
})
resp.on('end',()=>{
console.log(data)
})
}).on('error',(err)=>{
console.log("Error: " + err.message)
})
obj.write(xml)
obj.end()
The SOAP envelope/XML file:
<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ndf="https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl">
<soapenv:Header/>
<soapenv:Body>
<ndf:LatLonListZipCode soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<zipCodeList xsi:type="xsd:string">90210</zipCodeList>
</ndf:LatLonListZipCode>
</soapenv:Body>
</soapenv:Envelope>
and the .bat file - for testing:
:: curl options: -H is for Header --data allows file parameters
curl -H "soapAction: \"https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl#LatLonListCityNames\"" -H "Content-Type: text/xml;charset=UTF-8" --data #latlonzipcode.xml https://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php > response.xml
The response I receive from the service:
403
{ server: 'AkamaiGHost',
'mime-version': '1.0',
'content-type': 'text/html',
'content-length': '320',
expires: 'Wed, 18 Jul 2018 14:18:05 GMT',
date: 'Wed, 18 Jul 2018 14:18:05 GMT',
connection: 'close' }
<HTML><HEAD>
<TITLE>Access Denied</TITLE>
</HEAD><BODY>
<H1>Access Denied</H1>
You don't have permission to access "http://graphical.weather.gov/xml/SOAP_server/ndfdXMLserver.php" on this server.<P>
Reference #18.7fd23017.1531923485.f45e7526
</BODY>
</HTML>
The batch file works perfectly. Any help would be great. Thanks.
UPDATE
After Googling around I found this. So I added the header User-Agent : headerTest to my options... And finally got a response, unfortunately it was
the WSDL.

As stated in my update above, my original problem was due to not using https and that the web service was blocking requests without a User-Agent header. As for the WSDL file being returned as the response, I mistakenly used GET in my options and forgot to correct it. Finally I suspected that something was going on with writing the XML to the body and found that there was an issue - I found that answer here. Here is the corrected code:
const https = require('https')
const fs = require('fs')
const xml = fs.readFileSync('latlonzipcode.xml','utf-8')
const options = {
hostname : 'graphical.weather.gov',
port : 443,
path : '/xml/SOAP_server/ndfdXMLserver.php',
method : 'POST',
headers : {
'User-Agent' : 'sampleTest',
'Content-Type' : 'text/xml;charset=utf-8',
'soapAction' : 'https://graphical.weather.gov/xml/DWMLgen/wsdl/ndfdXML.wsdl#LatLonListZipCode'
}
}
var obj = https.request(options,(resp)=>{
let data = ''
fs.writeFile('server.log',resp.statusCode+"\n"+JSON.stringify(resp.headers),(err)=>{
err ? console.log(err) : console.log('log file written')
})
resp.on('data',(chunk)=>{
data += chunk
})
resp.on('end',()=>{
fs.writeFile('soap-response.xml',data,(err)=>{
err ? console.log(err) : console.log('data file written')
})
console.log(data)
})
}).on('error',(err)=>{
console.log("Error: " + err.message)
})
/**
* '.write()' is not being used:
* obj.write(xml) ? console.log('op success') : console.log('error!')
* obj.end()
*/
obj.end(xml) ? console.log('op success') : console.log('error!')
Node.js has finally got me excited about JavaScript. Thanks.

Related

How to write curl 'PUT' request in node with 'request' module

I have this curl request working.
curl -v "https://developer.api.autodesk.com/oss/v2/buckets/:bucketName/objects/"
-X "PUT" -H "Authorization: Bearer tokenGoesHere"
-H "Content-Type: application/octet-stream" -T "forupload.rvt"
How can I write this in node with npm request module.
I tried the following with 'request' and 'fs'.
I get back "Token is not provided in the request".
function uploadFile(bucketData){
var uri = 'https://developer.api.autodesk.com/oss/v2/buckets/' + bucketData['bucketKey'] + '/objects/'
var authorizationHeader = ' Bearer ' + bucketData['token'] // this works in other post/get requests
var contentTypeHeader = 'application/octet-stream'
var streamTarget = 'C:\\Users\\architech\\Desktop\\Forge Node\\Test.rvt';
console.log(uri)
console.log(authorizationHeader)
console.log(contentTypeHeader)
console.log(streamTarget)
// console output:
// https://developer.api.autodesk.com/oss/v2/buckets/bucketpqglrzt/objects/
// Bearer ....token....
// application/octet-stream
// C:\Users\architech\Desktop\Forge Node\Test.rvt
request.put(
{
url: uri,
// preambleCRLF: true,
// postambleCRLF: true,
multipart:
[
{
'Authorization': authorizationHeader,
'Content-Type': contentTypeHeader,
body: fs.createReadStream(streamTarget)
},
]
},
function(error, response, body){
if(!error){
console.log(body);
}else{
console.log(error);
}
})
}
After trying several approaches, while I couldn't reproduce your specific problem, the trouble I had was with the binary attachment loading properly. Because createReadStream() runs asynchronously, it doesn't really seem to work the way the request docs say it should when added to the multipart or formData keys. Not sure why this is?
I got it working first using http://requestb.in - comparing the curl request to the same request constructed with Node. Here is the final, working version:
var request = require('request')
fs = require('fs')
var options = {
uri: 'https://developer.api.autodesk.com/oss/v2/buckets/<yourBucket>/objects/<yourFile.ext>',
headers: {
'Content-Type': 'application/octet-stream',
'Authorization': 'Bearer <token>'
}
}
fs.createReadStream(__dirname + '/<fileName.ext>').pipe(request.put(options, function(err, response, body) {
console.log(body)
/*
{
"bucketKey" : "< yourBucket>",
"objectId" : "urn:adsk.objects:os.object:brandontestbucket2/skyscpr1.3ds",
"objectKey" : "<fileName.ext>",
"sha1" : "...redacted...",
"size" : 43791,
"contentType" : "application/octet-stream",
"location" : "https://developer.api.autodesk.com/oss/v2/buckets/< yourBucket>/objects/<fileName.ext>"
}
*/
}))

How to send a push notification from Node.js using REST API in MobileFirst Foundation 8?

Who knows what did I wrong in implementing this on a Node.js server?
The parameter were valid and it worked with the Poster on my local Mac.
Node.js and MFP 8 Beta are running locally on the Mac.
Here is the code for the server.js file and the steps are:
prepare the header
MFP Settings
create post options
create the JSON object for MFP Push
Do the POST call using http
write the json Push Data
app.post('/award', function(req, res){
var notificationMessage = req.body.message;
// prepare the header
// MFP Settings
var theAuthorization = "Bearer eyJhbGciOiJSUzI1NiIsImp…….Wg";
var appname = 'com.ionicframework.checkapp';
var http = require('http');
var theHost = 'localhost'; // here only the domain name
var thePort = 9080;
var thePath = 'imfpush/v1/apps/' + appname + '/messages';
var theMethode = 'POST';
var postheaders = {
'Authorization' : theAuthorization ,
'Content-Type' : 'application/json'
};
// the post options
var optionspost = {
host : theHost,
port : thePort,
path : thePath,
method : theMethode,
headers : postheaders
};
// create the JSON object for MFP Push
var jsonObject = JSON.stringify({"message":{"alert" :notificationMessage}});
console.info('---> Options prepared:');
console.info(optionspost);
console.info('---> Do the POST call');
// do the POST call using http
var reqPost = http.request(optionspost, function(res) {
console.log("---> statusCode: ", res.statusCode);
console.log("---> headers: ", res.headers);
res.on('data', function(d) {
console.info('---> POST result:\n');
process.stdout.write(d);
console.info('\n\n---> POST completed');
});
});
// write the json Push Data
reqPost.write(jsonObject);
reqPost.end();
reqPost.on('error', function(e) {
console.error(e);
});
res.end("OK");
});
I get the statusCode:400 and this is console output:
Options prepared:
{ host: 'localhost',
port: 9080,
path: 'imfpush/v1/apps/com.ionicframework.checkapp/messages',
method: 'POST',
headers:
{ 'Content-Type': 'application/json',
Authorization: 'Bearer eyJhbGciOiJSUzI1NiIsImp3ayI6......DjbgjqVz5JFVcT8i5k_JWg' } }
---> Do the POST call
---> statusCode: 400
---> headers: { 'content-length': '0',
connection: 'Close',
date: 'Wed, 22 Jun 2016 12:02:50 GMT' }
These were my information sources:
https://isolasoftware.it/2012/05/28/call-rest-api-with-node-js/ and
https://mobilefirstplatform.ibmcloud.com/tutorials/en/foundation/8.0/notifications/sending-push-notifications/
Thanks #Idan for the text validation and #Nathan for the comment.
I found the problem and now it works.
I changed the order of the request preparation and some changes in the code.
prepare the header
MFP Settings
create the JSON object for MFP Push -> Moved UP
create post options -> Moved Down
Do the POST call using http
write the json Push Data
Code changes:
Insert 'Content-Length': Buffer.byteLength(jsonObject) inside the header.
Adding a slash to the path var thePath = '/imfpush/v1/apps/' + appname + '/messages';

Sending RESTClient Firefox POST and try the same in node.js

I'm sending the following post with FireFox rest client:
POST /WSPublic.asmx HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 462
Host: host
Connection: close
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body><ContadoresTR xmlns="https://xxxxx"><Usuario>user</Usuario><Contrasena>password</Contrasena><NInstalacion>inst</NInstalacion><VersionFicheroEsperado>1</VersionFicheroEsperado></ContadoresTR></soap12:Body></soap12:Envelope>
It works, and I receive the response from the server.
Looking in Wireshark conversations, I see that firstly the RESTClient sends the following stream:
...........fe....0..S.... ..L0g....!...z.P. _....N.im3....8.q.'...6.9.....p>. .+./.
...........3.2.9./.5.
.......c........
ges.leako.com......
.................#..3t.....!...h2-14.spdy/3.1.spdy/3.http/1.1.........
Then I try to do the same using node.js. The HTTP client sends the same post and I don't receive response from the server. Looking at the Wireshark conversations, I see that the first HTTP Client stream the format is different from the RESTClient of firefox.
POST /WSPublic.asmx HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 462
Host: host
Connection: close
<?xml version="1.0" encoding="utf-8"?>
<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap12="http://www.w3.org/2003/05/soap-envelope"><soap12:Body><ContadoresTR xmlns="https://xxxxxx"><Usuario>user</Usuario><Contrasena>password</Contrasena><NInstalacion>inst</NInstalacion><VersionFicheroEsperado>1</VersionFicheroEsperado></ContadoresTR></soap12:Body></soap12:Envelope>
Here the node.js script:
var http = require("http")
var body = '<?xml version="1.0" encoding="utf-8"?>'
+'<soap12:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
+'xmlns:xsd="http://www.w3.org/2001/XMLSchema"'
+'xmlns:soap12="http://www.w3.org/2003/05/soap-envelope">'
+'<soap12:Body>'
+'<ContadoresTR xmlns="https://ges.leako.com/WSPublic">'
+'<Usuario>xxx</Usuario>'
+'<Contrasena>xxx</Contrasena>'
+'<NInstalacion>xxx</NInstalacion>'
+'<VersionFicheroEsperado>x</VersionFicheroEsperado>'
+'</ContadoresTR>'
+'</soap12:Body>'
+'</soap12:Envelope>';
var postRequest = {
host: "ges.leako.com",
path: "/WSPublic.asmx",
port: 443,
method: "POST",
headers: {
'Content-Type': 'application/soap+xml; charset=utf-8',
'Content-Length': Buffer.byteLength(body),
'Connection': 'keep-alive'
}
};
var buffer = "";
var req = http.request( postRequest, function( res ) {
console.log( res.statusCode );
var buffer = "";
res.on( "data", function( data ) { buffer = buffer + data; } );
res.on( "end", function( data ) { console.log( buffer ); } );
});
req.write( body );
req.end();
What I'm doing wrong? Why Firefox send the POST format different than the node.js HTTP Client, and which is that format?
Thanks in advance.
Apart from the 'keep-alive' 'Connection' header and the 'Content-type' one, everything seems fine as mentioned by #mithunsatheesh in this other question how to post XML data in node.js http.request but I guess you were already aware of that since the code is pretty similar in both cases :)

status code 400 with no error object when uploading to box

I'm trying to use the request.jslibrary to upload a file to box.com using request.post.
I consistently get a return code of 400 and a null body in the response. Not sure how to get at the actual error that box is seeing. The err argument to the callback is null, so there is a response from box.com, but with a statuscode of 400 and a null body.
FYI, the upload succeeds using curl, so the auth token etc. is fine.
I pointed the function below to http://echo.200please.com', and it seems the HTTP POST request I'm sending out is fine.
How do I get to see what error is being seen by box?
request = require"request");
UploadFile = function(filename, callback) {
var formData = {
attributes: JSON.stringify( {
name: filename,
parent: { id: '' + 2764913765 }
}),
file: fs.createReadStream('./temp.bin')
}
var options = {
url: 'https://upload.box.com/api/2.0/files.content',
headers: { Authorization: 'Bearer ' + tokens.access_token},
formData: formData
}
request.post(options,
function(err, response, body) {
if (err) {
console.log('Error Uploading the file');
} else {
console.log('returned:' + body + JSON.stringify(response.headers))
}
});
If I change the URL to point to echo.200please.com, the response I get from echo.200please.com is below, which seems to be the correct format for a file upload request.
> POST / HTTP/1.0
Host: echo.200please.com
Connection: close
Content-Length: 1951
Authorization: Bearer bVPDzG8PgIVRNoqb5LOzD61h6NXhJ6h0
content-type: multipart/form-data; boundary=--------------------------799592280904953105406767
----------------------------799592280904953105406767
Content-Disposition: form-data; name="attributes"
{"name":"testchunkname.1","parent":{"id":"2764913765"}}
----------------------------799592280904953105406767
Content-Disposition: form-data; name="file"; filename="temp.bin"
Content-Type: application/octet-stream
<... file data ...>
OK ... I found the bug :-)
It's a typo in the url
in my program it got set to api/2.0/files.content whereas the correct path in the url should be api/2.0/files/content

node.js request fails for umts Stick Webserver (huawei)

i´m trying to get websites / xml objects from the huawei umts stick internal web gui.
I´ve written a wrapper in c using libcurl which works fine. Now i want to port this to node using request.
When i call a url with curl from console like this:
curl -G "http://192.168.1.1/api/monitoring/status"
I get normal result:
<?xml version="1.0" encoding="UTF-8"?>
<response>
<ConnectionStatus>901</ConnectionStatus>
<SignalStrength>99</SignalStrength>
<SignalIcon>5</SignalIcon>
<CurrentNetworkType>4</CurrentNetworkType>
<CurrentServiceDomain>3</CurrentServiceDomain>
<RoamingStatus>0</RoamingStatus>
<BatteryStatus></BatteryStatus>
<BatteryLevel></BatteryLevel>
<simlockStatus></simlockStatus>
</response>
When i try to call this site with request:
var request = require("request");
var options = {
url: "http://192.168.1.1/api/monitoring/status"
};
request.get(options, function(error, response, body) {
if(error)
{
console.log(error);
}
console.log("statusCode: " + response.statusCode);
console.log("statusText: " + response.statusText);
console.log(body);
});
I got an 400 Error:
statusCode: 400
statusText: undefined
<HTML><HEAD>
<TITLE>IPWEBS - 400 Bad Request</TITLE>
</HEAD>
<BODY><H2>400 Bad Request</H2>
<P>The request generated an error response.</P>
</BODY>
</HTML>
Any idea on this subject?
It could be that curl is sending a header that the server requires. Try changing your options to:
var options = {
url: "http://192.168.1.1/api/monitoring/status",
headers: {
'User-Agent': 'curl/7.30.0',
'Accept': '*/*'
}
}

Resources