SOAP Request to Wemo switch from Pebble returns status 500 - soap

Been trying to write a pebble app for wemo switches, currently this is the code i'm using:
function WemoRequest(callback) {
if (SOAPData === false || SOAPData === undefined) {
console.log("Invalid SOAP data: " + JSON.stringify(SOAPData));
return;
}
var url = "http://192.168.1.230:49153/upnp/control/basicevent1";
try {
var request = new XMLHttpRequest();
request.open("POST", url, false);
request.setRequestHeader("SOAPAction", "urn:Belkin:service:basicevent:1#GetBinaryState");
request.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
request.onreadystatechange = function() {
if (request.readyState == 4 && request.status === 200 && callback) {
callback(request, SOAPData);
}else{console.log("Status: "+request.status + " State: "+request.readyState+" Callback: "+callback);}
};
var packet = '<?xml version="1.0" encoding="utf-8"?>'+
'<s:Envelope xmls:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'+
'<s:Body>'+
'<u:GetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"></u:GetBinaryState>'+
'</s:Body>'+
'</s:Envelope>';
request.send(packet);
} catch (error) {
console.log("Error in XMLHttpRequest: " + error);
}}
I currently get status 500 from OnReadyStateChange and have no idea what I'm doing wrong. If this isn't enough code, app code is available here:https://github.com/dmf444/Webble

So...I know this is from 4 years ago lol, but I found this during a google search and just found the answer, so I figured I would respond for that reason: I think your header just needs an extra set of quotes around "urn:Belkin:service:basicevent:1#SetBinaryState" so that the string specifying the soapaction literally starts and ends with quotes.
I'm working in Python (because that's what all the kids seem to be doing these days), but I too was getting the 500 error until I made a very subtle change (the single quote marks around my double quotes) and almost cried tears of joy when my light turned off:
"SOAPACTION": '"urn:Belkin:service:basicevent:1#SetBinaryState"'
So here's the working version of the code (in Python lol):
import http.client
#Variables (value=on/off, ipaddress=address of your wemo)
value = 0 #1=ON, 0=OFF
ipAddress = "192.168.0.108"
#Build the SOAP Envelope (data)
data = '<?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:SetBinaryState xmlns:u="urn:Belkin:service:basicevent:1"><BinaryState>' + str(value) + '</BinaryState></u:SetBinaryState></s:Body></s:Envelope>'
#Build the Header (headers)
headers = {"Content-type" : 'text/xml; charset="utf-8"', "SOAPACTION": '"urn:Belkin:service:basicevent:1#SetBinaryState"', "Content-Length": len(data)}
#Send request and check response data (resp_data)
conn = http.client.HTTPConnection(ipAddress, 49153)
conn.request("POST", "/upnp/control/basicevent1", data, headers)
response = conn.getresponse()
resp_data = response.read()
if response.status == 200:
conn.close()
print("SUCCESS!")
elif response.status == 403:
print("ERROR: 403 (FORBIDDEN)")
else:
print("ERROR: " + str(response.status))

Related

How to call Microsoft Graph REST API with groovy-wslite

I am trying to call Microsoft Graph API on groovy script using Java libraries. However, even though partly success, I still have some serious issues using it within my current project, so I think about trying to call the the REST API using groovy-wslite.
This is my current code for getting access token:
def authorizeHost = "https://login.microsoftonline.com"
def authorizePath = "/${azureSetting.getTenantID()}/oauth2/v2.0/authorize?"
try {
RESTClient client = new RESTClient(authorizeHost)
def params = [
"client_id":azureSetting.getClientID(),
"scope": "https://graph.microsoft.com/.default",
"response_type": "code"
]
def response = client.post(
path: authorizePath,
)
{
type ContentType.JSON
json params
}
LOGGER.info("Success: " + (response.statusCode == 200));
LOGGER.info("Output: (" + response.contentType + ") " + response.text);
} catch (RESTClientException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
LOGGER.info("Error: " + sw.toString());
}
The response from the log:
AADSTS900144: The request body must contain the following parameter: 'client_id'.
How can I change the above code, so that Microsoft Graph REST API can recognize my sending content and send back the access token.
UPDATE: After trying around, I found out that the body os post method should be as below:
type "application/x-www-form-urlencoded"
urlenc client_id: azureSetting.getClientID(),
scope: "https://graph.microsoft.com/.default",
response_type: "code"
according to doc https://learn.microsoft.com/en-us/graph/auth-v2-user#token-request your request should have Content-Type: application/x-www-form-urlencoded
you are trying to send json instead
here is your code but pointing to a test httpbin.org server and it could show what exactly you are sending to server
there is a minor change: ContentType.JSON -> ContentType.URLENC
#Grab(group='com.github.groovy-wslite', module='groovy-wslite', version='1.1.3', transitive=false)
import wslite.rest.*
//just for test
def azureSetting = [ getClientID:{-> "12345"} ]
def LOGGER = [info:{x-> println x}]
//redefined host and url
def authorizeHost = "HTTP://httpbin.org"
def authorizePath = "/post"
try {
RESTClient client = new RESTClient(authorizeHost)
def params = [
"client_id":azureSetting.getClientID(),
"scope": "https://graph.microsoft.com/.default",
"response_type": "code"
]
def response = client.post(
path: authorizePath,
)
{
type ContentType.URLENC // <-- THE ONLY CHANGE IN YOUR CODE
json params
}
LOGGER.info("Success: " + (response.statusCode == 200));
LOGGER.info("Output: (" + response.contentType + ") " + response.text);
} catch (RESTClientException e) {
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
LOGGER.info("Error: " + sw.toString());
}

ionic 3 header not sending Authorizaqtion 'bearer "token"' to server

Im doing a login screen that takes a username and password.
if the login was successful the server will return a token.
then im trying to call another function to get user info but the authorization header is not being passed.
im trying my server method on postman and its working fine so i believe the problem is in the headers. May someone please advise me on what should be done?
let url = urlConst.Login;
let params1 = new HttpParams();
let loader = this.loadingcontroller.create({
content: stringEngConst.signinngin
});
let attributes = {
username: this.uname.value.toLowerCase(),
password: this.password.value,
grant_type: "password"
};
var headers = new HttpHeaders();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
let body = 'username=' + this.uname.value.toLowerCase() + '&password=' + this.password.value + '&grant_type=password';
let data: Observable < any > = this.http.post(url, body, {
headers: headers
});
loader.present().then(() => {
data.subscribe(result => {
if (result.access_token != null) {
this.signintoken = result.access_token;
this.storage.set(storageConst.SIGN_IN_TOKEN, result.token_type + " " + result.access_token);
headers.append('Authorization', 'Bearer ' + this.signintoken);
let url1 = 'http://localhost:57940/API/Account/GetUserInfo/';
let info: Observable < any > = this.http.get(url1, {
headers: headers
});
info.subscribe(result => {
/*Do Something*/
});
}
Please Note that result.access_token != null is true. and i am successfully getting the token back. But it is not being passed again to the second url (info)
Looks like this SO post may solve things for you: https://stackoverflow.com/a/47805759/6599076
You may want to use:
headers = headers.append('Authorization', 'Bearer ' + this.signintoken);
You are using the same headers as for the first http request:
var headers = new HttpHeaders();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
Depending on your end point for the subsequent call it might be that you need to set headers differently:
Try creating new headers with
var headers2 = new HttpHeaders();
headers.append('Content-Type', 'application/json');
Or get rid of Content-Type completely depending on what your end point expects.
Also if you are using Ionic 3 its worth to check which Http module you are using (HttpClient or the older one) as there are some differences in how these tend to handle request options.

protractor promises - querying an API using "request"

I am trying to use protractor to call an api - it will return some JSON to me and I want to assert against it. I thought I had this working, until I tried to take it further and realised I hadn't got it right, but having a bit of a time trying to work out why.
I have placed some console.logs in and expected the sequence to be 1,2,3 however it appears to be 3 (test finished) then 2 and 1. So I suspect a promise issue.
code below:
'use strict';
var request = require('request');
var path = require('path');
var info;
//var fname = null;
var fname = 'joe';
describe("Sample test", function() {
var request = require('request');
var options = {
method: 'GET',
url: 'URL here',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: '{ "pay_load": [] }'
};
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
info = JSON.parse(body);
console.log('in the callback now');
//console.log('body :' + body);
//var count = Object.keys(info).length;
//console.log('body len:' + count);
//console.log('info :' + info);
fname = info.firstname;
console.log('firstname1 : ' + info.firstname);
console.log('firstname2 : ' + fname);
} else {
console.log('there was some error');
}
}
it("proves the API is alive - firstname is null", function() {
request(options, callback);
//expect(fname).toBe(null);
console.log('firstname3 : ' + fname);
//expect(fname).toBe(null);
//var common = new Common();
//common.checkForAPI();
});
So in my head I thought I would see "in the callback", then "firstname1", "firstname2" and finally "firstname3"
No, firstname3 will always get printed first, the way you have it. The reason for it as that all http requests in nodejs are async, so while your request is processing (or in flight), firstname3 will be printed. Then console.logs in your request callback.
Edit1 - Addressing the comment
Simple example which would print firstname1,2,3 in sequence (tested)
var request = function(cb) {
//basically call your request stuff and then when you are done call cb
console.log('firstname 1');
console.log('firstname 2');
cb();
};
request(function() {
console.log('firstname 3');
});
This prints
firstname 1
firstname 2
firstname 3
Or you can use a third party library called async and use async.tryEach to run tasks in series.
async.tryEach([
function getDataFromFirstWebsite(callback) {
// Try getting the data from the first website
callback(err, data);
},
function getDataFromSecondWebsite(callback) {
// First website failed,
// Try getting the data from the backup website
callback(err, data);
}
],
// optional callback
function(err, results) {
Now do something with the data.
});

Google Cloud Storage File Upload - Requested page not found. [404]

I am trying to upload a file to Google Cloud Storage using Json API. I am posting the request to below url with the file attachment.
https://www.googleapis.com/upload/storage/v1/b/mybucket/o?uploadType=media&name=solarsystemlrg.png
But I am getting Requested page not found. [404] Error. When I use the below Url, I am able to list the images stored in the bucket (Just to be sure that there are no access issues and bucket name is correct).
https://www.googleapis.com/storage/v1/b/mybucket/o
I have set the headers.
'Authorization' :'Bearer ' + accessToken,
'Content-Type' : contentType,
'Content-Length' : inputFile.size
Please find the code snippet below.
$.ajax({
url: targetUrl,
headers: reqHeaders,
type: 'POST',
data: reqFormWithDataFile,
async: false,
cache: false,
dataType: 'jsonp',
useDefaultXhrHeader: false,
processData: false,
success: function (response) {
alert('File Upload Successful');
},
error: function (jqXHR, exception) {
var msg = '';
if (jqXHR.status === 0) {
msg = 'Not connect.\n Verify Network.';
} else if (jqXHR.status == 404) {
msg = 'Requested page not found. [404]';
} else if (jqXHR.status == 500) {
msg = 'Internal Server Error [500].';
} else if (exception === 'parsererror') {
msg = 'Requested JSON parse failed.';
} else if (exception === 'timeout') {
msg = 'Time out error.';
} else if (exception === 'abort') {
msg = 'Ajax request aborted.';
} else {
msg = 'Uncaught Error.\n' + jqXHR.responseText;
}
alert(msg);
}
});
Do I need to use a different URL? Or is there any other setting required? Please help.
That's the right URL, so long as you replace mybucket with your actual bucket name. After reading through jquery.ajax(), I emulated what I think is the behavior by adding &callback=foo, due to dataType: 'jsonp' and &_=1474410231688 because cache: false, and issued the request via curl and that produced a valid object with a valid callback. Can you log the entire jqXHR to see more of the status?

Problems uploading jpg with OneDrive Rest Api

For this HTML5 phone App I have to use the OneDrive REST API.
I managed to upload the file, but the file up on the server is not in .jpg format and won't display in a jpg viewer. After logging in through the REST API and getting a token back, I used XMLHttpRequest to PUT the file. I've tried passing it up as an ArrayBuffer and as a base64 encoded string. In each case the file makes it there, but is not decoded properly. I figured I needed to tell the webserver how to decode the file with "request.setRequestHeader('Content-Type', 'image/jpg')" ,but I get back the following error message from the OneDrive server:
"error": {
"code": "request_body_invalid_media_type",
"message": "The Content-Type header 'text/plain' isn't supported."
}
this.uploadFile = function (token, fileUri,fileName, fileTools, success, fail) {
var me = app.log('||Microsoft.uploadFile||');
fileTools.readFileContent(fileUri, 'dataUrl', gotData, fileError);
function fileError(err) {
app.logError(me + '::fileError:::' + err);
}
function gotData(base64String) {
var request = new XMLHttpRequest;
app.log(me + '::token::' + token);
request.open("PUT", "https://apis.live.net/v5.0/me/skydrive/files/" + fileName + "?access_token=" + token, true);
request.setRequestHeader('Content-Type', 'text/plain');
//request.setRequestHeader('Content-Type', 'image/jpg');
//request.setRequestHeader('Content-Transfer-Encoding', 'base64;charset=utf-8');
request.onload = function (e) {
app.log(request.responseText);
success(e);
};
request.onerror = function (e) {
app.log(me + '::7::');
fail(e.error.message);
};
app.log(me + '::8::' + base64String.substr(0,100));
var b = new Base64Stuff();
var aBuffer = b.base64ToBuffer(b.removeBase64jpgHeader(base64String));
request.send(aBuffer);
//request.send(base64String);
}
}
try
request.setRequestHeader('Content-Type', '');