ESP 8266 Multiple Get calls on same Client? - https

I'm trying to make Multiple GET calls using the same client. I've tried multiple things. New Variables, New instances. Closing Clients. The second Stock Call doesnt go through ever. It fails at "while (client.connected())" on the second Call. It Doesnt get to returning headers.
Any Ideas?
Code look like this
void loop()
{
WiFiClientSecure client;
//Stock
String payload;
// Use WiFiClientSecure class to create TLS connection
Serial.print("connecting to ");
Serial.println(host);
Serial.printf("Using fingerprint '%s'\n", fingerprint);
client.setFingerprint(fingerprint);
if (!client.connect(host, httpsPort))
{
Serial.println("connection failed");
client.stop();
//return;
}
//AAPL
String url = "/api/v1/quote?symbol=AAPL&token=XXXX";
Serial.print("requesting URL: ");
Serial.println(url);
client.print(String("GET ") + url + " HTTP/1.0\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
while (client.connected())
{
String line = client.readStringUntil('\n');
// String line = client.readStringUntil('\r');
Serial.println(line);
if (line == "\r")
{
Serial.println("headers received");
payload = client.readStringUntil('\r');
//break;
}
}
Serial.println("payload");
Serial.println(payload);
// String line = client.readString();
//JsonObject& obj = doc.parseObject(payload);
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, payload);
// Test if parsing succeeds.
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
// return;
client.stop();
}
//{"c":23.35,"d":-0.73,"dp":-3.0316,"h":24.6986,"l":23.25,"o":24.54,"pc":24.08,"t":1627588802}
double currentprice = doc["c"];
double pctchg = doc["d"];
// Print values.
Serial.println(currentprice);
Serial.println(pctchg);
Serial.println("closing connection");
client.stop();
delay(20000);
//SPY
String spyurl = "/api/v1/quote?symbol=SPY&token=XXXX";
Serial.print("requesting URL: ");
Serial.println(spyurl);
client.print(String("GET ") + spyurl + " HTTP/1.0\r\n" +
"Host: " + host + "\r\n" +
"User-Agent: BuildFailureDetectorESP8266\r\n" +
"Connection: close\r\n\r\n");
Serial.println("request sent");
String spypayload;
while (client.connected())
{
String spyline = client.readStringUntil('\n');
// String line = client.readStringUntil('\r');
Serial.println(spyline);
if (spyline == "\r")
{
Serial.println("headers received");
spypayload = client.readStringUntil('\r');
//break;
}
}
Serial.println("spypayload");
Serial.println(spypayload);
// String line = client.readString();
//JsonObject& obj = doc.parseObject(payload);
StaticJsonDocument<200> spydoc;
DeserializationError spyerror = deserializeJson(spydoc, spypayload);
// Test if parsing succeeds.
if (spyerror) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(spyerror.f_str());
// return;
client.stop();
}
//{"c":23.35,"d":-0.73,"dp":-3.0316,"h":24.6986,"l":23.25,"o":24.54,"pc":24.08,"t":1627588802}
double SPYcurrentprice = spydoc["c"];
double SPYpctchg = spydoc["d"];
// Print values.
Serial.println(SPYcurrentprice);
Serial.println(SPYpctchg);
Serial.println("closing connection");
client.stop();

I'm an idiot.
Needed to keep the connection open on the first call
"Connection: Keep-Alive\r\n\r\n");

Related

HttpClient exception in Windows service, but not in WinForms and Console application

I am experiencing an issue where an async call works in my WinForms and Console test applications, but not when I implement the same code in my intended target format - a Windows service.
I always get the "A task was canceled" exception - and I can't figure out why :|
System.Threading.Tasks.TaskCanceledException: A task was canceled.
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at TotalArchiveService.CustomerServices.<ValidateCustomerCoreWSGen2>d__2.MoveNext() in C:\DeveloperArea\Dev\src\TotalArchiveService\CustomerServices.cs:line 123
Using Fiddler, I can see that the Windows service doesn't even call the service. At least there are no traces of it in the Fiddler log.
The following are code examples, where the two first ones are the WinForms and Console variants respectively. The last on is the non functioning Windows service.
In the Windows Service, the ValidateCustomer method is called in the OnElapsedTime method of the Windows service. I have tried several intervals, as I suspected that there were some kind of overlap of calls due to the async here, but it doesn't change anything. Even if it had been, I'd thought that I'd seen some traces of the first call in Fiddler, but there's nothing.
I am using .NET Framework 4.8 for the service and WinForms variants. .NET 6.0 for the Console app.
Any help or suggestions would be greatly appreciated.
WinForms
private static async Task<string> ValidateCustomerCoreWSGen2(string customerNumber)
{
REMOVED SECTION WHERE INTERNAL PARAMS WERE UPDATED FROMN CONFIG.
}
catch (Exception _ex)
{
_status = "CONFIG_ERROR";
}
try
{
using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(_timeout) })
{
// Create HTTP request.
var customerBuilder = new UriBuilder(new Uri($"{_endpoint}"));
var customerRequest = new HttpRequestMessage(HttpMethod.Post, customerBuilder.Uri);
// Set SOAP action
customerRequest.Headers.Add("SOAPAction", "");
// SOAP body content
string xmlSOAP = GetXmlSOAP("CUSTOMERREAD", _sourceApplication, _destinationApplication, _function, _version, _username, _channel, _orgId, _orgUnit, customerNumber);
customerRequest.Content = new StringContent(xmlSOAP, Encoding.UTF8, "text/xml");
// Add signature headers to request object
await SignHttpRequestMessage(customerRequest);
// Call service
var customerResponse = await client.SendAsync(customerRequest);
//Response handling
if (customerResponse.IsSuccessStatusCode)
{
// Do what you want with response body
var responseBody = await customerResponse.Content.ReadAsStringAsync();
_status = "CUSTOMER_EXISTS";
}
else
{
_status = "CUSTOMER_READ_EXCEPTION";
var responseBody = await customerResponse.Content.ReadAsStringAsync();
var message = $"Response returned with status {customerResponse.StatusCode}. Reason: {customerResponse.ReasonPhrase}";
}
}
}
catch (Exception _ex)
{
_status = "SERVICE_ERROR";
}
return _status;
}
static async Task SignHttpRequestMessage(HttpRequestMessage request)
{
// externalize configuration of these
string certPath = "";
string keyStorePassword = "";
string keyId = "";
certPath = Path.GetFullPath(#"c:\cert2\cert.pfx"); // path to keystorefile
keyStorePassword = "REMOVED";
keyId = "REMOVED";
X509Certificate2Collection certs = new X509Certificate2Collection();
X509Certificate2 cert = new X509Certificate2(certPath, keyStorePassword, X509KeyStorageFlags.DefaultKeySet | X509KeyStorageFlags.Exportable);
var services = new ServiceCollection()
.AddHttpMessageSigning()
.UseKeyId(keyId)
.UseSignatureAlgorithm(SignatureAlgorithm.CreateForSigning(cert, HashAlgorithmName.SHA256))
.UseDigestAlgorithm(HashAlgorithmName.SHA256)
.UseUseDeprecatedAlgorithmParameter()
.UseNonce(false)
.UseHeaders()
.Services;
using (var serviceProvider = services.BuildServiceProvider())
{
using (var signerFactory = serviceProvider.GetRequiredService<IRequestSignerFactory>())
{
var requestSigner = signerFactory.CreateFor(keyId);
await requestSigner.Sign(request);
}
}
request.Headers.Add("Signature", request.Headers.Authorization.ToString());
request.Headers.Authorization = null;
}
private static string GetXmlSOAP(string method, string sourceApplication, string destinationApplication, string function, string version, string username, string channel, string orgId, string orgUnit, string customerNumber)
{
string _xmlSOAP = "";
if (method.ToUpper() == "CUSTOMERREAD")
{
_xmlSOAP = #"<?xml version=""1.0"" encoding=""utf-8""?>
<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:wsc=""http://REMOVED""
xmlns:urn=""urn:REMOVED""
xmlns:urn1=""urn:REMOVED""
xmlns:urn2=""urn:REMOVED"">
<soapenv:Header>
<wsc:AutHeader>
<wsc:SourceApplication>" + sourceApplication + #"</wsc:SourceApplication>
<wsc:DestinationApplication>" + destinationApplication + #"</wsc:DestinationApplication>
<wsc:Function>" + function + #"</wsc:Function>
<wsc:Version>" + version + #"</wsc:Version>
<wsc:ClientContext>
<wsc:userid>" + username + #"</wsc:userid>
<wsc:credentials/>
<wsc:channel>" + channel + #"</wsc:channel>
<wsc:orgid>" + orgId + #"</wsc:orgid>
<!--Optional:-->
<wsc:orgunit>" + orgUnit + #"</wsc:orgunit>
<!--Optional:-->
<wsc:customerid>" + customerNumber + #"</wsc:customerid>
<!--Optional:-->
<wsc:locale>no_NO</wsc:locale>
<wsc:ip>127.0.0.1</wsc:ip>
</wsc:ClientContext>
</wsc:AutHeader>
</soapenv:Header>
<soapenv:Body>
<urn:customerReadRequest>
<urn:readQualification>
<urn1:internationalCustomerKey>
<urn2:internationalCustomerNumber>" + customerNumber + #"</urn2:internationalCustomerNumber>
</urn1:internationalCustomerKey>
</urn:readQualification>
</urn:customerReadRequest>
</soapenv:Body>
</soapenv:Envelope>";
}
return _xmlSOAP;
}
private void cmdCustomerRead_Click(object sender, EventArgs e)
{
lblStatus.Text = "Status:";
//ValidateCustomerCoreWSGen2(tbCustomerNumber.Text.Trim());
CallValidateCustomerAsync(tbCustomerNumber.Text.Trim());
}
private async void CallValidateCustomerAsync(string customerNumber)
{
string result = await ValidateCustomerCoreWSGen2(customerNumber);
lblStatus.Text = "Status: " + result;
}
Console
static async Task ExampleRequest()
{
var timeout = 30;
try
{
using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(timeout) })
{
int textidx = 2;
// URL to soap service
var endpointUrlCustomer = "https://REMOVED";
// Create HTTP request.
var customerBuilder = new UriBuilder(new Uri($"{endpointUrlCustomer}"));
var customerRequest = new HttpRequestMessage(HttpMethod.Post, customerBuilder.Uri);
// set SOAP action
customerRequest.Headers.Add("SOAPAction", "");
// set SOAP body content
Console.WriteLine();
Console.WriteLine("************************* CUSTOMER ***********************");
string xmlSOAP = GetXmlSOAP("CUSTOMER", textidx);
customerRequest.Content = new StringContent(xmlSOAP, Encoding.UTF8, "text/xml");
// Add signature headers to request object
await SignHttpRequestMessage(customerRequest, textidx);
Console.WriteLine("Signed request HTTP");
Console.WriteLine("-----------------------------------------");
Console.WriteLine(customerRequest + Environment.NewLine);
Console.WriteLine("Signed request XML");
Console.WriteLine("-----------------------------------------");
Console.WriteLine(customerRequest.Content.ReadAsStringAsync().Result + Environment.NewLine);
// Perform request
Console.WriteLine("Send request");
Console.WriteLine("-----------------------------------------");
var customerResponse = await client.SendAsync(customerRequest);
Console.WriteLine();
Console.WriteLine("Response HTTP");
Console.WriteLine("-----------------------------------------");
Console.WriteLine(customerResponse + Environment.NewLine);
Console.WriteLine("Response result XML");
Console.WriteLine("-----------------------------------------");
Console.WriteLine(customerResponse.Content.ReadAsStringAsync().Result + Environment.NewLine);
if (customerResponse.IsSuccessStatusCode)
{
// Do what you want with response body
var responseBody = await customerResponse.Content.ReadAsStringAsync();
}
else
{
var responseBody = await customerResponse.Content.ReadAsStringAsync();
var message = $"Response returned with status {customerResponse.StatusCode}. Reason: {customerResponse.ReasonPhrase}";
throw new Exception(message);
}
}
}
catch (HttpRequestException e)
{
throw e;
}
}
static async Task SignHttpRequestMessage(HttpRequestMessage request, int testIdx)
{
// externalize configuration of these
string certPath = "";
string keyStorePassword = "";
string keyId = "";
if (testIdx == 1)
{
keyStorePassword = "REMOVED";
keyId = "REMOVED";
}
if (testIdx == 2)
{
certPath = Path.GetFullPath(#"c:\cert2\cert.pfx"); // path to keystorefile
keyStorePassword = "REMOVED";
keyId = "REMOVED";
}
else if (testIdx == 3)
{
certPath = Path.GetFullPath(#"REMOVED"); // path to keystorefile
keyStorePassword = "REMOVED";
keyId = "REMOVED";
}
X509Certificate2Collection certs = new X509Certificate2Collection();
X509Certificate2 cert = new X509Certificate2(certPath, keyStorePassword, X509KeyStorageFlags.DefaultKeySet | X509KeyStorageFlags.Exportable);
var services = new ServiceCollection()
.AddHttpMessageSigning()
.UseKeyId(keyId)
.UseSignatureAlgorithm(SignatureAlgorithm.CreateForSigning(cert, HashAlgorithmName.SHA256))
.UseDigestAlgorithm(HashAlgorithmName.SHA256)
.UseUseDeprecatedAlgorithmParameter()
.UseNonce(false)
.UseHeaders()
.Services;
using (var serviceProvider = services.BuildServiceProvider())
{
using (var signerFactory = serviceProvider.GetRequiredService<IRequestSignerFactory>())
{
var requestSigner = signerFactory.CreateFor(keyId);
await requestSigner.Sign(request);
}
}
request.Headers.Add("Signature", request.Headers.Authorization.ToString());
request.Headers.Authorization = null;
}
static string GetXmlSOAP(string operation, int testIdx)
{
string xmlSOAP = "";
if (operation == "CUSTOMER")
{
if (testIdx == 1)
{
REMOVED
}
if (testIdx == 2)
{
xmlSOAP = #"<?xml version=""1.0"" encoding=""utf-8""?>
<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:wsc=""http://REMOVED""
xmlns:urn=""urn:REMOVED""
xmlns:urn1=""urn:REMOVED""
xmlns:urn2=""urn:REMOVED"">
<soapenv:Header>
<wsc:AutHeader>
<wsc:SourceApplication>REMOVED</wsc:SourceApplication>
<wsc:DestinationApplication>REMOVED</wsc:DestinationApplication>
<wsc:Function>REMOVED</wsc:Function>
<wsc:Version>REMOVED</wsc:Version>
<wsc:ClientContext>
<wsc:userid>REMOVED</wsc:userid>
<wsc:credentials/>
<wsc:channel>REMOVED</wsc:channel>
<wsc:orgid>REMOVED</wsc:orgid>
<wsc:orgunit>REMOVED</wsc:orgunit>
<wsc:customerid>REMOVED</wsc:customerid>
<wsc:locale>no_NO</wsc:locale>
<wsc:ip>127.0.0.1</wsc:ip>
</wsc:ClientContext>
</wsc:AutHeader>
</soapenv:Header>
<soapenv:Body>
<urn:customerReadRequest>
<urn:readQualification>
<urn1:internationalCustomerKey>
<urn2:internationalCustomerNumber>REMOVED</urn2:internationalCustomerNumber>
</urn1:internationalCustomerKey>
</urn:readQualification>
</urn:customerReadRequest>
</soapenv:Body>
</soapenv:Envelope>";
}
if (testIdx == 3)
{
REMOVED
}
}
}
Windows service
internal class CustomerServices
{
private static bool _extendedLogging = true;
public static string ValidateCustomer(string customerNumber)
{
string _status = "";
string _servicesType = CommonMethods.GetAppSetting("ServicesType");
//TODO: Check format, ref. "UNSUPPORTED_FORMAT" in HandleValidateCustomerException
//TODO: Check existing, ref. "CUSTOMER_NOT_FOUND" in HandleValidateCustomerException
if (_servicesType == "COREWSGEN2")
{
_status = ValidateCustomerCoreWSGen2(customerNumber).GetAwaiter().GetResult();
}
return _status;
}
private static async Task<string> ValidateCustomerCoreWSGen2(string customerNumber)
{
string _status = "";
string _username = "";
string _orgId = "";
string _orgUnit = "";
string _channel = "";
string _sourceApplication = "";
string _destinationApplication = "";
string _function = "";
string _version = "";
int _timeout = 30;
string _endpoint = "";
string _values = "";
try
{
_extendedLogging = (CommonMethods.GetAppSetting("ExtendedLogging").ToUpper() == "TRUE" ? true : false);
_values += "ExtendedLogging" + Environment.NewLine;
_username = CommonMethods.GetAppSetting("Username");
_values += "Username" + Environment.NewLine;
_orgId = CommonMethods.GetAppSetting("OrgId");
_values += "OrgId" + Environment.NewLine;
_orgUnit = CommonMethods.GetAppSetting("OrgUnit");
_values += "OrgUnit" + Environment.NewLine;
_channel = CommonMethods.GetAppSetting("CoreWSGen2Channel");
_values += "CoreWSGen2Channel" + Environment.NewLine;
_sourceApplication = CommonMethods.GetAppSetting("CoreWSGen2SourceApplication");
_values += "CoreWSGen2SourceApplication" + Environment.NewLine;
_destinationApplication = CommonMethods.GetAppSetting("CoreWSGen2DestinationApplication");
_values += "CoreWSGen2DestinationApplication" + Environment.NewLine;
_function = CommonMethods.GetAppSetting("CoreWSGen2Function");
_values += "CoreWSGen2Function" + Environment.NewLine;
_version = CommonMethods.GetAppSetting("CoreWSGen2Version");
_values += "CoreWSGen2Version" + Environment.NewLine;
_timeout = Int32.Parse(CommonMethods.GetAppSetting("CoreWSGen2TimeoutSeconds"));
_values += "CoreWSGen2Version" + Environment.NewLine;
_endpoint = CommonMethods.GetAppSetting("CustomerServicesEndpointAddress");
if (_extendedLogging)
{
Logging.LogAction("Application settings used for customer read:" + Environment.NewLine
+ "-------------------------------------------------" + Environment.NewLine
+ "Username = " + _username + Environment.NewLine
+ "OrgId = " + _orgId + Environment.NewLine
+ "OrgUnit = " + _orgUnit + Environment.NewLine
+ "Channel = " + _channel + Environment.NewLine
+ "SourceApplication = " + _sourceApplication + Environment.NewLine
+ "DestinationApplication = " + _destinationApplication + Environment.NewLine
+ "Function = " + _function + Environment.NewLine
+ "Version = " + _version + Environment.NewLine
+ "Timeout (seconds) = " + _timeout + Environment.NewLine
+ Environment.NewLine
+ "Endpoint = " + _endpoint + Environment.NewLine);
}
}
catch (Exception _ex)
{
_status = "CONFIG_ERROR";
Logging.LogException(new Exception("CustomerServices - Error when reading configuration file. Successfully read values: " + Environment.NewLine + _values + Environment.NewLine, _ex.InnerException));
}
try
{
using (var client = new HttpClient { Timeout = TimeSpan.FromSeconds(_timeout) })
{
// Create HTTP request.
var customerBuilder = new UriBuilder(new Uri($"{_endpoint}"));
var customerRequest = new HttpRequestMessage(HttpMethod.Post, customerBuilder.Uri);
// Set SOAP action
customerRequest.Headers.Add("SOAPAction", "");
// SOAP body content
string xmlSOAP = GetXmlSOAP("CUSTOMERREAD", _sourceApplication, _destinationApplication, _function, _version, _username, _channel, _orgId, _orgUnit, customerNumber);
customerRequest.Content = new StringContent(xmlSOAP, Encoding.UTF8, "text/xml");
// Add signature headers to request object
await SignHttpRequestMessage(customerRequest);
// Call service
var customerResponse = await client.SendAsync(customerRequest);
if (_extendedLogging)
{
Logging.LogAction("Response header:" + Environment.NewLine + customerResponse + Environment.NewLine);
Logging.LogAction("Response content:" + Environment.NewLine + customerResponse.Content.ReadAsStringAsync().Result + Environment.NewLine);
}
//Response handling
if (customerResponse.IsSuccessStatusCode)
{
// Do what you want with response body
var responseBody = await customerResponse.Content.ReadAsStringAsync();
// Log response content if extended logging
if (_extendedLogging)
{
Logging.LogAction(responseBody);
}
_status = "CUSTOMER_EXISTS";
}
else
{
_status = "CUSTOMER_READ_EXCEPTION";
var responseBody = await customerResponse.Content.ReadAsStringAsync();
var message = $"Response returned with status {customerResponse.StatusCode}. Reason: {customerResponse.ReasonPhrase}";
Logging.LogException(new Exception(message));
}
}
}
catch (Exception _ex)
{
_status = "SERVICE_ERROR";
Logging.LogException(_ex);
}
return _status;
}
static async Task SignHttpRequestMessage(HttpRequestMessage request)
{
// externalize configuration of these
string certPath = "";
string keyStorePassword = "";
string keyId = "";
certPath = Path.GetFullPath(#"c:\cert2\cert.pfx"); // path to keystorefile
keyStorePassword = "internal-sls-test";
keyId = "73ae28ed2f31";
X509Certificate2Collection certs = new X509Certificate2Collection();
X509Certificate2 cert = new X509Certificate2(certPath, keyStorePassword, X509KeyStorageFlags.DefaultKeySet | X509KeyStorageFlags.Exportable);
var services = new ServiceCollection()
.AddHttpMessageSigning()
.UseKeyId(keyId)
.UseSignatureAlgorithm(SignatureAlgorithm.CreateForSigning(cert, HashAlgorithmName.SHA256))
.UseDigestAlgorithm(HashAlgorithmName.SHA256)
.UseUseDeprecatedAlgorithmParameter()
.UseNonce(false)
.UseHeaders()
.Services;
using (var serviceProvider = services.BuildServiceProvider())
{
using (var signerFactory = serviceProvider.GetRequiredService<IRequestSignerFactory>())
{
var requestSigner = signerFactory.CreateFor(keyId);
await requestSigner.Sign(request);
}
}
request.Headers.Add("Signature", request.Headers.Authorization.ToString());
request.Headers.Authorization = null;
if (_extendedLogging)
{
Logging.LogAction("Signed request header:" + Environment.NewLine + request + Environment.NewLine);
Logging.LogAction("Signed request content:" + Environment.NewLine + request.Content.ReadAsStringAsync().Result + Environment.NewLine);
}
}
private static string GetXmlSOAP(string method, string sourceApplication, string destinationApplication, string function, string version, string username, string channel, string orgId, string orgUnit, string customerNumber)
{
string _xmlSOAP = "";
if (method.ToUpper() == "CUSTOMERREAD")
{
_xmlSOAP = #"<?xml version=""1.0"" encoding=""utf-8""?>
<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
xmlns:wsc=""http://edb.com/ws/WSCommon_v22""
xmlns:urn=""urn:srv.cus.corews.enterprise.fs.evry.com:ws:customer:v20_1""
xmlns:urn1=""urn:srv.cus.corews.enterprise.fs.evry.com:domain:customer:v20_1""
xmlns:urn2=""urn:corews.enterprise.fs.evry.com:domain:common:v8"">
<soapenv:Header>
<wsc:AutHeader>
<wsc:SourceApplication>" + sourceApplication + #"</wsc:SourceApplication>
<wsc:DestinationApplication>" + destinationApplication + #"</wsc:DestinationApplication>
<wsc:Function>" + function + #"</wsc:Function>
<wsc:Version>" + version + #"</wsc:Version>
<wsc:ClientContext>
<wsc:userid>" + username + #"</wsc:userid>
<wsc:credentials/>
<wsc:channel>" + channel + #"</wsc:channel>
<wsc:orgid>" + orgId + #"</wsc:orgid>
<!--Optional:-->
<wsc:orgunit>" + orgUnit + #"</wsc:orgunit>
<!--Optional:-->
<wsc:customerid>" + customerNumber + #"</wsc:customerid>
<!--Optional:-->
<wsc:locale>no_NO</wsc:locale>
<wsc:ip>127.0.0.1</wsc:ip>
</wsc:ClientContext>
</wsc:AutHeader>
</soapenv:Header>
<soapenv:Body>
<urn:customerReadRequest>
<urn:readQualification>
<urn1:internationalCustomerKey>
<urn2:internationalCustomerNumber>" + customerNumber + #"</urn2:internationalCustomerNumber>
</urn1:internationalCustomerKey>
</urn:readQualification>
</urn:customerReadRequest>
</soapenv:Body>
</soapenv:Envelope>";
}
return _xmlSOAP;
}
}

ESP32 OTA via ETH

I have an running and working system which is an ESP32 with an LAN8720 to communicate over the internet.
Now just plane HTTP requests (via the WiFiClientSecure client) work like a charm. But I also need (over https) to update the device.
Now I currently have this code:
#include <Arduino.h>
#include <Update.h>
#include <HTTPUpdate.h>
WiFiClientSecure otaClient;
Serial.println("Preparing to update");
// Do OTA update
otaClient.setInsecure(); //skip verification of SSL cert
if (!otaClient.connect(DIGITAL_HQ_BASE_URL, 443)) {
Serial.println("Could not connect.");
}
otaClient.print("GET "); // watch the space!
otaClient.print(DIGITAL_HQ_BINARY_ENDPOINT); // API endpoint
otaClient.println(" HTTP/1.1"); // watch the space!
otaClient.print("Host: ");
otaClient.println(DIGITAL_HQ_BASE_URL);
otaClient.println("Connection: keep-alive"); // Don't close, since we need to perform OTA
otaClient.print("User-Agent: ");
otaClient.println(DIGITAL_HQ_USER_AGENT);
otaClient.println("Cache-Control: no-cache");
otaClient.println();
unsigned long timeout = millis();
while (otaClient.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println("Client Timeout !");
otaClient.stop();
return;
}
}
while (otaClient.available()) {
// read line till /n
String line = otaClient.readStringUntil('\n');
// remove space, to check if the line is end of headers
line.trim();
// if the the line is empty,
// this is end of headers
// break the while and feed the
// remaining `client` to the
// Update.writeStream();
if (!line.length()) {
//headers ended
break; // and get the OTA started
}
// Check if the HTTP Response is 200
// else break and Exit Update
if (line.startsWith("HTTP/1.1")) {
if (line.indexOf("200") < 0) {
Serial.println("Got a non 200 status code from server. Exiting OTA Update.");
break;
}
}
// extract headers here
// Start with content length
if (line.startsWith("Content-Length: ")) {
contentLength = atol((getHeaderValue(line, "Content-Length: ")).c_str());
Serial.println("Got " + String(contentLength) + " bytes from server");
}
// Next, the content type
if (line.startsWith("Content-Type: ")) {
String contentType = getHeaderValue(line, "Content-Type: ");
Serial.println("Got " + contentType + " payload.");
if (contentType == "application/octet-stream") {
isValidContentType = true;
}
}
}
Serial.println("contentLength : " + String(contentLength) + ", isValidContentType : " + String(isValidContentType));
if (contentLength && isValidContentType) {
// Check if there is enough to OTA Update
bool canBegin = Update.begin(contentLength);
// If yes, begin
if (canBegin) {
Serial.println("Begin OTA. This may take 2 - 5 mins to complete. Things might be quite for a while.. Patience!");
// No activity would appear on the Serial monitor
// So be patient. This may take 2 - 5mins to complete
size_t written = Update.writeStream(otaClient);
if (written == contentLength) {
Serial.println("Written : " + String(written) + " successfully");
} else {
Serial.println("Written only : " + ConvertFormatBytes(written) + "/" + ConvertFormatBytes(contentLength));
// retry??
// execOTA();
}
if (Update.end()) {
Serial.println("OTA done!");
if (Update.isFinished()) {
Serial.println("Update successfully completed. Rebooting.");
ESP.restart();
} else {
Serial.println("Update not finished? Something went wrong!");
}
} else {
Serial.println("Error Occurred. Error #: " + String(Update.getError()));
}
} else {
// not enough space to begin OTA
// Understand the partitions and
// space availability
Serial.println("Not enough space to begin OTA");
otaClient.stop();
}
} else {
Serial.println("There was no content in the response");
otaClient.stop();
}
This runs without errors, but is frozen on the Preparing to update console message. Anyone who has an idea what I'm doing wrong here?
The file NEEDS to come from an https domain.

How to wait for request to finish in Jmeter

I am currently new to Jmeter, and trying to create a Jmeter script to test how long a request takes to process and complete.
a) Authenticate using Token - Complete
b) Post Request - Complete - Returns 200
c) Get Request - Partially Completed
C: I am Trying to get be able to monitor this request to find out when its either completed failed etc.
I have created the Http Request Sample with a Get Request
I am able to get the Request 200 but it doesn't wait for completion
So running this in a console app, it waits for a certain time checking for status....
Is there a way to possibly write a code similar to the C# code in bean shell or groovy to wait. I was reading about while controller as well...
var result = WaitForBuildToComplete(dest, requestData, token, timeout);
static string GetStatus(string path, Token token)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(path);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "GET";
AddToken(token, httpWebRequest);
WebResponse response = httpWebRequest.GetResponse();
string responseFromServer = "";
using (Stream dataStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(dataStream);
responseFromServer = reader.ReadToEnd();
}
// Close the response.
response.Close();
return responseFromServer;
}
static int WaitForBuildToComplete(string dest, RequestData requestData, Token token, int
timeout)
{
if (timeout <= 0) return 0;
var path = $"{ConfigurationManager.AppSettings[dest]}/policy?id={requestData.id}";
var startTime = DateTime.Now;
do
{
var status = GetStatus(path, token);
var msg = JsonConvert.DeserializeObject<string>(status);
var requestStatus = JsonConvert.DeserializeObject<RequestStatus>(msg);
if (!string.IsNullOrEmpty(requestStatus.DllUrl))
{
Console.WriteLine($"\nResult dll at: {requestStatus.DllUrl}");
return 0;
}
if (requestStatus.Status.ToUpper() == "FAILED")
{
Console.WriteLine($"\nFAILED");
Console.WriteLine(requestStatus.Message);
return -1;
}
if (requestStatus.Status.ToUpper() == "FAILED_DATA_ERROR")
{
Console.WriteLine($"\nFAILED_DATA_ERROR");
Console.WriteLine(requestStatus.Message);
return -1;
}
if (requestStatus.Status.ToUpper() == "NOT_NEEDED")
{
Console.WriteLine($"\nNOT_NEEDED");
Console.WriteLine(requestStatus.Message);
return -1;
}
Console.Write(".");
System.Threading.Thread.Sleep(1000);
} while ((DateTime.Now - startTime).TotalSeconds < timeout);
Console.WriteLine("Time out waiting for dll.");
return -1;
}
I started by looking at JSR223 Sampler but wanted to see if there is a better and easier way to accomplish this.
List<String> sendRequest(String url, String method, Map<String,Object> body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
StringEntity entity = new StringEntity(new Gson().toJson(body), "UTF-8");
HttpUriRequest request = RequestBuilder.create(method)
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8")
.setEntity(entity)
.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n" + EntityUtils.toString(entity) + "\n";
HttpClientBuilder.create().build().withCloseable {httpClient ->
httpClient.execute(request).withCloseable {response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res );
return Arrays.asList(req, res);
}
}
}
List sendGet(String url, Map<String,String> body) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(2000)
.setSocketTimeout(3000)
.build();
RequestBuilder requestBuilder = RequestBuilder.get()
.setConfig(requestConfig)
.setUri(url)
.setHeader(HttpHeaders.CONTENT_TYPE, "application/json;charset=UTF-8");
body.forEach({key, value -> requestBuilder.addParameter(key, value)});
HttpUriRequest request = requestBuilder.build();
String req = "REQUEST:" + "\n" + request.getRequestLine() + "\n" + "Headers: " +
request.getAllHeaders() + "\n";
HttpClientBuilder.create().build().withCloseable {httpClient ->
httpClient.execute(request).withCloseable {response ->
String res = "RESPONSE:" + "\n" + response.getStatusLine() + "\n" + "Headers: " +
response.getAllHeaders() + "\n" +
(response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : "") + "\n";
System.out.println(req + "\n" + res );
return Arrays.asList(req, res);
}
}
}
The approach which is normally used in JMeter is placing your request under the While Controller which will be checking the Status value which in its turn can be fetched from the response using a suitable Post-Processor so the request will be retried unless the "Status" changes to some value which you expect (or times out)
If you place the whole construction under the Transaction Controller you will get the whole time for the status to change.
Example test plan outline:

Raw ESCP Printing through Socket JAVA

I have this Raw ESC/POS command for LX-300+, and i want to print it through Print Server using Socket.
String escp = " '\x1B' + '\x40', // initialize the printer, reset printer to defaults " +
" '\x1B' + '\x78' + '\x31', // Set Print Quality NLQ " +
" '\x1B' + '\x6B' + '\x31', // Select typeface San serif " +
" '\x1B' + '\x43' + '\x00' + '\x06', // set Page Length to 6 Inch " +
" '\x1B' + '\x4D', // Select 12 cpi Spacing " +
" '\x1B' + '\x45', // SET Bold Font ";
Question is, can we parse that String of escp with Socket? i use this code,
Socket socket = null;
OutputStream output = null;
BufferedReader reader = null;
try {
socket = new Socket("10.0.5.30", 9100);
socket.setSoTimeout(5000);
output = socket.getOutputStream();
reader = new BufferedReader(new java.io.InputStreamReader(socket.getInputStream()));
} catch (UnknownHostException e) {
// TODO: handle exception
}
if (socket != null && output != null) {
try
{
output.write(escp.getBytes());
output.flush();
socket.shutdownOutput();
output.close();
socket.close();
}
catch (Exception e)
{
System.out.println(e.toString());
}
}
The result is, printer LX-300 is not converting the ESC/POS Command. Just print the String inside escp variable. Any solution to this? i'm using linux 18.04 FYI.

ESP32 WifiClientSecure no response

I'm working on a project using a google script to publish images from an ESP32-CAM to google drive.
I keep getting the error "no response", no matter how long I set the wait peroid to. I tried using http and https(wificlient and wificlientsecure) but it doesn't work no matter what.
What could be the issue?
WiFiClientSecure clienthttps;
Serial.println("Connect to " + String(myDomain));
if (clienthttps.connect(myDomain, 443)) {
Serial.println("Connection successful");
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
delay(1000);
ESP.restart();
return;
}
char *input = (char *)fb->buf;
char output[base64_enc_len(3)];
String imageFile = "";
for (int i = 0; i < fb->len; i++) {
base64_encode(output, (input++), 3);
if (i % 3 == 0) imageFile += urlencode(String(output));
}
String Data = myFilename + mimeType + myImage;
esp_camera_fb_return(fb);
Serial.println("Send a captured image to Google Drive.");
Serial.println("POST " + myScript + " HTTP/1.1");
Serial.println("Host: " + String(myDomain));
Serial.println("Content-Length: " + String(Data.length() + imageFile.length()));
Serial.println("Content-Type: application/x-www-form-urlencoded");
Serial.println(Data);
Serial.println();
clienthttps.println("POST " + myScript + " HTTP/1.1");
clienthttps.println("Host: " + String(myDomain));
clienthttps.println("Content-Length: " + String(Data.length() + imageFile.length()));
clienthttps.println("Content-Type: application/x-www-form-urlencoded");
clienthttps.println();
clienthttps.print(Data);
int Index;
for (Index = 0; Index < imageFile.length(); Index = Index + 1000) {
clienthttps.print(imageFile.substring(Index, Index + 1000));
}
Serial.println("Waiting for response.");
long int StartTime = millis();
while (!clienthttps.available()) {
Serial.print(".");
delay(100);
if ((StartTime + waitingTime) < millis()) {
Serial.println();
Serial.println("No response.");
//If you have no response, maybe need a greater value of waitingTime
break;
}
}
Serial.println();
while (clienthttps.available()) {
Serial.print(char(clienthttps.read()));
}
} else {
Serial.println("Connected to " + String(myDomain) + " failed.");
}
clienthttps.stop();
Note that in the latest "github.com/espressif/arduino-esp32" (as at 17Jan23) the command
"WiFiClientSecure.println();" (your "clienthttps.println()") seems to corrupt the SSL-buffer somehow, and although the command returns after a bit, the SSL-connection fails at that point (this didn't happen in earlier versions of the software).
The solution which worked for me was to ensure I at very least sent "WiFiClientSecure.println(" ");" (ie. " \r\n") as this seems to work.
(This solution appears also often necessary if sending data over a GPRS connection because in that instance a ".println()" seems to be ingored!)

Resources