Getting "EIdHTTPProtocolException with message 'HTTP/1.1 400 BAD REQUEST'" exception - ssl

I am working on a VCL application and I have to integrate Twilio using its REST API:
https://www.twilio.com/docs/usage/your-request-to-twilio
Here is my code:
pair<bool, String> SMSTwilio::SendMessage(TComponent* Owner,
String ToNumber, String FromNumber, String Message)
{
if(Message.Length() > MESSAGE_LIMIT) {
ShowMessage("Message must have " + IntToStr(MESSAGE_LIMIT) +
" or fewer characters. Cannot send message with " +
IntToStr(Message.Length()) + "characters.");
}
AccountSID = "AC2d48*****************0deb52";
AuthToken = "9e28ec***************c0126e";
Message = "Hi";
FromNumber = "+1740****95";
ToNumber = "+9*****791";
String URI = "https://api.twilio.com/2010-04-01/Accounts/"
+ AccountSID +
"/Messages";
TStringList* params = new TStringList();
params->Add("From=" + FromNumber);
params->Add("To=" + ToNumber);
params->Add("Body=" + Message);
TIdHTTP* HTTP = new TIdHTTP(Owner);
HTTP->Request->Connection = "Keep-Alive";
HTTP->Request->ContentType = "application/x-www-form-urlencoded";
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(Owner);
Handler->SSLOptions->Method = sslvTLSv1;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result = "";
__try {
try {
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
Result = HTTP->Post(URI, params);
isSuccess = true;
} catch(Exception &e) {
isSuccess = false;
Result = e.Message;
}
}
__finally {
delete HTTP;
delete params;
}
return make_pair(isSuccess, Result);
}
I am getting an EIdHTTPProtocolException with message "HTTP/1.1 400 BAD REQUEST" thrown by Result = HTTP->Post(URI, params);.

You are posting to the wrong URL.
You are posting to .../Messages but you need to post to .../Messages.json instead (notice the .json at the end), per Twilio's Message Resource documentation:
Create a Message resource
POST https://api.twilio.com/2010-04-01/Accounts/{AccountSid}/Messages.json
To send a new outgoing message, make an HTTP POST to this Messages list resource URI.
Also, although not errors per-say, there are some other issues with your code:
your Owner parameter is unnecessary. Since you are creating and destroying your TIdHTTP object in the same function, there is no need to assign an Owner to it at all. And it would be more useful to assign that TIdHTTP object as the Owner for the TIdSSLIOHandlerSocketOpenSSL object, instead of some unknown external Owner.
you are not returning an error to the caller if the Message is too long to send.
you are not adequately protecting your objects from leaks if something bad happens (why not use C++ smart pointers instead of try..finally?).
your catch() should be catching the Exception object by const reference.
you don't need Request->Connection = "Keep-Alive" since you are closing the connection after the Post() is finished, you are not actually using a keep-alive.
you should be using the SSLOptions->SSLVersions property instead of the SSLOptions->Method property. That will then allow you to enable sslvTLSv1_1 and sslvTLSv1_2, since many servers are phasing out TLS 1.0 nowadays, so you should prepare for that sooner rather than later.
With that said, try something more like this:
#include <utility>
#include <memory>
std::pair<bool, String> SMSTwilio::SendMessage(
String ToNumber, String FromNumber, String Message)
{
if (Message.Length() > MESSAGE_LIMIT) {
String msg = Format(_D("Message must have %d or fewer characters. Cannot send message with %d characters."), ARRAYOFCONST(( MESSAGE_LIMIT, Message.Length() )) );
//ShowMessage(msg);
return std::make_pair(false, msg);
}
String AccountSID = _D("AC2d48*****************0deb52");
String AuthToken = _D("9e28ec***************c0126e");
//Message = _D("Hi");
//FromNumber = _D("+1740****95");
//ToNumber = _D("+9*****791");
String URI = Format(_D("https://api.twilio.com/2010-04-01/Accounts/%s/Messages.json"), ARRAYOFCONST(( AccountSID )) );
std::unique_ptr<TStringList> params(new TStringList); // or std::auto_ptr prior to C++11
params->Add(_D("From=") + FromNumber);
params->Add(_D("To=") + ToNumber);
params->Add(_D("Body=") + Message);
std::unique_ptr<TIdHTTP> HTTP(new TIdHTTP(nullptr)); // or std::auto_ptr prior to C++11
HTTP->ReadTimeout = 5000;
HTTP->ConnectTimeout = 5000;
//HTTP->Request->Connection = _D("Keep-Alive");
HTTP->Request->ContentType = _D("application/x-www-form-urlencoded");
HTTP->Request->BasicAuthentication = true;
HTTP->Request->Username = AccountSID;
HTTP->Request->Password = AuthToken;
TIdSSLIOHandlerSocketOpenSSL* Handler = new TIdSSLIOHandlerSocketOpenSSL(HTTP.get());
Handler->SSLOptions->SSLVersions = TIdSSLVersions() << sslvTLSv1 << sslvTLSv1_1 << sslvTLSv1_2;
HTTP->IOHandler = Handler;
bool isSuccess = false;
String Result;
try {
Result = HTTP->Post(URI, params);
isSuccess = true;
}
catch (const Exception &e) {
isSuccess = false;
Result = e.Message;
}
return std::make_pair(isSuccess, Result);
}

Related

FileStore.CreateFile returns ntStatus = 3221226071

I am using this SMBLibrary. Related to this closed issue, I sometimes get ntStatus = 3221226071 when I attempt to FileStore.CreateFile(). What does "DFS pathname not on local server" mean? If I keep trying, eventually it will work. Leads me to believe some resources are being held or not released/disconnected. Any ideas here?
"SMBLibrary" Version="1.4.8"
Here is my code:
[Fact]
public void Unit_Test_To_Test_SMBLibrary()
{
var server = "myRemoteServer";
var shareName = "shareddir";
var windowsPath = "Data\\Folder1\\unittest";
var random = new System.Random();
var filename = "createdBySmbclient" + random.Next(1, 10).ToString() + ".txt";
var domain = "my.domain";
var username = "myUser";
var password = "--put secret password here--";
var client = new SMB2Client();
bool isConnected = client.Connect(server, SMBTransportType.DirectTCPTransport);
if(isConnected)
{
try
{
NTStatus ntStatus = client.Login(domain, username, password);
if (ntStatus == NTStatus.STATUS_SUCCESS)
{
ISMBFileStore fileStore = client.TreeConnect(shareName, out ntStatus);
object fileHandle;
FileStatus fileStatus;
var windowsPathWithFile = Path.Combine(windowsPath, filename);
// 1st, create empty file.
ntStatus = fileStore.CreateFile(
out fileHandle,
out fileStatus,
windowsPathWithFile,
AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE,
0,
ShareAccess.None,
CreateDisposition.FILE_OPEN_IF,
CreateOptions.FILE_NON_DIRECTORY_FILE,
null
);
// create file contents and get the bytes
byte[] filebytes = Encoding.ASCII.GetBytes("hello world");
// 2nd, write data to the newly created file
if (ntStatus == NTStatus.STATUS_SUCCESS && fileStatus == FileStatus.FILE_CREATED)
{
int numberOfBytesWritten;
ntStatus = fileStore.WriteFile(out numberOfBytesWritten, fileHandle, 0, filebytes);
fileStore.FlushFileBuffers(fileHandle);
fileStore.CloseFile(fileHandle);
fileStore.Disconnect();
_logger.LogDebug(string.Format("Export successful: {0}", windowsPathWithFile));
}
else
{
throw new Exception(string.Format("ERROR: ntStatus = {0}, fileStatus = {1}", ntStatus, fileStatus));
}
}
}
finally
{
client.Logoff();
client.Disconnect();
}
}
}

I want to capture all warnings while importing a solution programatically in CRM 2016. In the response object I am not getting any such information

var importSolutionRequest = new ImportSolutionRequest
{
ImportJobId = Guid.NewGuid(),
CustomizationFile = fileBytes,
OverwriteUnmanagedCustomizations = true,
PublishWorkflows = true,
SkipProductUpdateDependencies = true,
};
var response = (ImportSolutionResponse)Service.Execute(importSolutionRequest);
I am not getting any useful information in this response object. What changes should I do to get warnings in this object, which occured while importing solution?
You have to query the ImportJob to get the results you want (https://msdn.microsoft.com/en-us/library/gg327847.aspx).
From the SDK (https://msdn.microsoft.com/en-us/library/gg509050.aspx):
// Monitor import success
byte[] fileBytesWithMonitoring = File.ReadAllBytes(ManagedSolutionLocation);
ImportSolutionRequest impSolReqWithMonitoring = new ImportSolutionRequest()
{
CustomizationFile = fileBytes,
ImportJobId = Guid.NewGuid()
};
_serviceProxy.Execute(impSolReqWithMonitoring);
Console.WriteLine("Imported Solution with Monitoring from {0}", ManagedSolutionLocation);
ImportJob job = (ImportJob)_serviceProxy.Retrieve(ImportJob.EntityLogicalName, impSolReqWithMonitoring.ImportJobId, new ColumnSet(new System.String[] { "data", "solutionname" }));
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(job.Data);
String ImportedSolutionName = doc.SelectSingleNode("//solutionManifest/UniqueName").InnerText;
String SolutionImportResult = doc.SelectSingleNode("//solutionManifest/result/#result").Value;
Console.WriteLine("Report from the ImportJob data");
Console.WriteLine("Solution Unique name: {0}", ImportedSolutionName);
Console.WriteLine("Solution Import Result: {0}", SolutionImportResult);
Console.WriteLine("");
// This code displays the results for Global Option sets installed as part of a solution.
System.Xml.XmlNodeList optionSets = doc.SelectNodes("//optionSets/optionSet");
foreach (System.Xml.XmlNode node in optionSets)
{
string OptionSetName = node.Attributes["LocalizedName"].Value;
string result = node.FirstChild.Attributes["result"].Value;
if (result == "success")
{
Console.WriteLine("{0} result: {1}",OptionSetName, result);
}
else
{
string errorCode = node.FirstChild.Attributes["errorcode"].Value;
string errorText = node.FirstChild.Attributes["errortext"].Value;
Console.WriteLine("{0} result: {1} Code: {2} Description: {3}",OptionSetName, result, errorCode, errorText);
}
}

Guid.TryParse vs SqlGuid.Parse

Using .Net framework 4, I have following input string
String s = "9330e655-63d4-4aee-be79-505554256bd3"
I want to write a function that will return true or false as to whether or not any input string is a valid SqlGuid:
Method 1:
' Parse to validate ...
ok = true
try
s_uid = SqlGuid.Parse( s )
catch e as Exception
ok = false
end try
return ok
However, the ASP.Net framework also provides the Guid.TryParse() method, ie:
Method 2:
' Parse to validate ...
ok = Guid.TryParse( s )
My question: Which is more efficient and what do most use to validate SQL GUIDs (Method 1 or 2)?
If you're just checking validity then you can use either method, and Guid.TryParse will allow you to validate without doing expensive exception handling.
Be aware, however, that the string representations of Guid and SqlGuid are not the same, so a string generated from a Guid should not be used to create a SqlGuid since it will result in a different GUID value.
best practice would be to use the build-in TryParse but if you want to look at the speed/performance itself here some quick benchmark.
don't forget to build as Release and don't run it from visual studio.
using System;
using System.Data.SqlTypes;
using System.Text.RegularExpressions;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var regex = new Regex(#"\b[A-F0-9]{8}(?:-[A-F0-9]{4}){3}-[A-F0-9]{12}\b", RegexOptions.IgnoreCase);
string s = "9330e655-63d4-4aee-be79-505554256bd3";
SqlGuid resultSql;
Guid result;
var sw = System.Diagnostics.Stopwatch.StartNew();
bool valid;
valid = true;
for (int i = 0; i < 500000; ++i)
{
try
{
resultSql = SqlGuid.Parse(s);
valid &= true;
}
catch
{
valid = false;
}
}
sw.Stop();
Console.WriteLine("sql try-catch {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
try
{
result = Guid.Parse(s);
valid &= true;
}
catch
{
valid = false;
}
}
sw.Stop();
Console.WriteLine("guid try-catch {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
valid &= Guid.TryParse(s, out result);
}
sw.Stop();
Console.WriteLine("tryparse {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
sw = System.Diagnostics.Stopwatch.StartNew();
valid = true;
for (int i = 0; i < 500000; ++i)
{
valid &= regex.IsMatch(s);
}
sw.Stop();
Console.WriteLine("regex {0}ms all valid {1}", sw.ElapsedMilliseconds, valid);
Console.ReadKey();
}
}
}

CloudStack: Unable to verify user credentials and/or request signature

I am working on CloudStack API now and I have the problem about making the API request. I always got "{ "listtemplatesresponse" : {"errorcode":401,"errortext":"unable to verify user credentials and/or request signature"} }" even though I change the parameter.
This error occurs in some commands that require the parameter and this is the command that I use:
command=listTemplates&templatefilter=featured
I don't know what I did wrong since it works with others. Here is the code I use to make the API request:
try {
String encodedApiKey = URLEncoder.encode(apiKey.toLowerCase(), "UTF-8");
ArrayList<String> sortedParams = new ArrayList<String>();
sortedParams.add("apikey="+encodedApiKey);
StringTokenizer st = new StringTokenizer(apiUrl, "&");
while (st.hasMoreTokens()) {
String paramValue = st.nextToken().toLowerCase();
String param = paramValue.substring(0, paramValue.indexOf("="));
String value = URLEncoder.encode(paramValue.substring(paramValue.indexOf("=")+1, paramValue.length()), "UTF-8");
sortedParams.add(param + "=" + value);
}
Collections.sort(sortedParams);
System.out.println("Sorted Parameters: " + sortedParams);
String sortedUrl = null;
boolean first = true;
for (String param : sortedParams) {
if (first) {
sortedUrl = param;
first = false;
} else {
sortedUrl = sortedUrl + "&" + param;
}
}
sortedUrl += "&response=json";
System.out.println("sorted URL : " + sortedUrl);
String encodedSignature = signRequest(sortedUrl, secretKey);
String finalUrl = host + "?" + apiUrl + "&response=json&apiKey=" + apiKey + "&signature=" + encodedSignature;
StringBuilder str = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(finalUrl);
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) { // Status OK
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
str.append(line);
}
System.out.println("str: "+str);
result = str.toString();
System.out.println("result: "+str);
}
else
System.out.println("Error response!!");
} catch (Throwable t) {
System.out.println(t);
}
And this is signRequest function:
public static String signRequest(String request, String key) {
try {
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacSHA1");
mac.init(keySpec);
mac.update(request.getBytes());
byte[] encryptedBytes = mac.doFinal();
return URLEncoder.encode(Base64.encodeBytes(encryptedBytes), "UTF-8");
} catch (Exception ex) {
System.out.println(ex);
}
return null;
}
Please feel free to ask me if you need more information. All comments and advice are welcome!
Have you tried sorting after you've added "&response=json" to the list of parameters?
E.g.
try {
String encodedApiKey = URLEncoder.encode(apiKey.toLowerCase(), "UTF-8");
ArrayList<String> sortedParams = new ArrayList<String>();
sortedParams.add("apikey="+encodedApiKey);
sortedParams.add("response=json");
StringTokenizer st = new StringTokenizer(apiUrl, "&");
while (st.hasMoreTokens()) {
String paramValue = st.nextToken().toLowerCase();
String param = paramValue.substring(0, paramValue.indexOf("="));
String value = URLEncoder.encode(paramValue.substring(paramValue.indexOf("=")+1, paramValue.length()), "UTF-8");
sortedParams.add(param + "=" + value);
}
Collections.sort(sortedParams);
System.out.println("Sorted Parameters: " + sortedParams);
String sortedUrl = null;
boolean first = true;
for (String param : sortedParams) {
if (first) {
sortedUrl = param;
first = false;
} else {
sortedUrl = sortedUrl + "&" + param;
}
}
System.out.println("sorted URL : " + sortedUrl);
String encodedSignature = signRequest(sortedUrl, secretKey);
String finalUrl = host + "?" + apiUrl + "&response=json&apiKey=" + apiKey + "&signature=" + encodedSignature;
StringBuilder str = new StringBuilder();
HttpClient client = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(finalUrl);
HttpResponse response = client.execute(httpGet);
StatusLine statusLine = response.getStatusLine();
int statusCode = statusLine.getStatusCode();
if (statusCode == 200) { // Status OK
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
str.append(line);
}
System.out.println("str: "+str);
result = str.toString();
System.out.println("result: "+str);
}
else
System.out.println("Error response!!");
} catch (Throwable t) {
System.out.println(t);
}
Your API Key and Response parameters need to be part of the sorted Url used when signing, which they appear to be.
try changing
return URLEncoder.encode(Base64.encodeBytes(encryptedBytes), "UTF-8");
to
return URLEncoder.encode(Base64.encodeAsString(encryptedBytes), "UTF-8");

Unable to access xsjs file from browser

I am new to SAP HANA and trying to expose the .xsjs file data through the webbrowser with the following url:
hostname:80<instance#>/workspace/session/a00/data/services/retrieveData.xsjs
However, I am getting the following error when I try to access it:
This link seems to be broken We could not find the resource you're trying to access. It might be misspelled or currently unavailable
These are the files which I have created in the project explorer:
MYSCHEMA.hdbschema
schema_name="MYSCHEMA"
trendsData.hdbtable
table.schemaName = "MYSCHEMA";
table.tableType = COLUMNSTORE;
table.description = "NewDataSet Order trendsData";
table.columns = [
{name= "C"; sqlType = NVARCHAR; nullable = true; length=10; },
{name= "D"; sqlType = VARCHAR; nullable = true; length=5; },
{name= "DU"; sqlType = NVARCHAR; nullable = true; length=20; },
{name= "SA"; sqlType = DECIMAL; nullable = true; length=30; },
{name= "I"; sqlType = DECIMAL; nullable = true; length=30; },
{name= "G"; sqlType = DECIMAL; nullable = true; length=30; },
{name= "G"; sqlType = DECIMAL; nullable = true; length=20; },
{name= "STR"; sqlType = DECIMAL; nullable = true; length=30; }
];
table.primaryKey.pkcolumns = ["INVENTORY"];
orderId.hdbsequence
schema="MYSCHEMA";
start_with=2000000;
cycles=false;
depends_on_table="workspace.session.a00.data::trendData";
retrieveData.xsjs
$.response.contentType="text/html";
var output = "Helloworld";
var conn = $.db.getConnection();
var pstmt = conn.prepareStatement("select * from trendData");
var rs = pstmt.executeQuery();
if (!rs.next())
{
$.response.setBody( "Failed to retrieve data");
$.response.status = $.net.http.INTERNAL_SERVER_ERROR;
}
else
{
output=output + "This is the respose from my SQL: "
+ rs.getString(1);
}
rs.close();
pstmt.close();
conn.close();
$.response.setBody(output);
All the above files were succesfully committed and activated with out any error. Still, the error occurs in the webrowser.
Are you sure that the URL you've typed in the browser is properly built?
URL's should be built in the following way:
server:port/repository_path/file_name
A wrong path may be causing your problem. Please see example below:
host: hanacloud
port: 8000 (80 + instance_number)
SAP HANA Repository tree:
mdo ->
sap ->
sflight ->
test ->
test.xsjs
URL: hanacloud:8000/mdo/sap/sflight/test/test.xsjs
Your port number should be 8000 instead of 80 and make sure that is not blocked on the network, which is usually case, especially in office network
Your select statement does not specify a schema. In addition the table's catalog name is usually "package name::table name". In addition your table definition has two columns with the same name and an invalid primary key specification.
Thus I would expect that the select fails. As a first step I would suggest to try
$.response.contentType = "text/plain";
$.response.setBody('hello world');
$.response.status = $.net.http.OK;
Once you get this running you know that the web access works. My next step would be to wrap everything into some try / catch like so
var eString = "";
try {
//*
* your code goes here
*//
return; // do not forget this!
} catch (e) {
eString = "\nException.toString(): " + e.toString() + "\n";
var prop = "";
for (prop in e) {
eString += prop + ": " + e[prop] + "\n";
response.status = $.net.http.INTERNAL_SERVER_ERROR;
response.contentType = "plain/text";
response.setBody(eString);
return;
}
response.status = $.net.http.INTERNAL_SERVER_ERROR;
response.contentType = "plain/text";
response.setBody("something went badly wrong");
This would then allow to pinpoint where exactly your code fails.
Please do ensure that the .xsaccess and .xsapp files are present and the syntax. Also endure that the files are activated.