Converting string literal to JSON Array and sending using HTTP Post Request - c++

I'm trying to send a post request over an ESP32 WiFi module using an Arduino IDE. Although the response received is 200, I receive a formatting error with the JSON body object. How should I format the JSON object?
Here is what the original JSON object looks like that I need to send:
{
"method":"passthrough",
"params":{
"deviceId":"9006765C87CD29BC37447E490C4C91F819143376",
"requestData":"{\"system\":{\"set_relay_state\":{\"state\":1}}}"
}
}
And here is what I've tried in the Post Request:
HTTPClient http;
http.begin(serverName);
http.addHeader("Content-Type", "application/json");
int httpResponseCode = http.POST("{\"deviceId\":\"9006765C87CD29BC37447E490C4C91F819143376\",\"requestData\":\"{\"system\":{\"set_relay_state\":{\"state\":0}}}\"}");
Serial.print("HTTP Response code: ");
Serial.println(httpResponseCode);
Serial.print(http.getString());
http.end();
Here is the response:
{"error_code":-10100,"msg":"JSON format error"}HTTP Response code: 200
UPDATE
I originally thought I would only need to pass the params but here is a version I have tried passing the method and params. I still get the same results, however.
String json =
"({"
"\"method\":\"passthrough\","
"\"params\":{"
"\"deviceId\":\"9006765C87CD29BC37447E490C4C91F819143376\","
"\"requestData\":\"{\"system\":{\"set_relay_state\":{\"state\":1}}}\""
"}"
"})";
Using this json string - I have tried passing int httpResponseCode = http.POST(json); but that doesn't work either and I get the same error. I'm assuming I need to convert this string to a Json array before passing to htt.Post?

The value of requestData needs to escape the quotes within the string. Otherwise the payload that is sent is malformed JSON with the value of requestData terminated too early.
This can be done with:
http.POST("{\"method\":\"passthrough\",\"params\":{\"deviceId\":\"9006765C87CD29BC37447E490C4C91F819143376\",\"requestData\":\"{\\\"system\\\":{\\\"set_relay_state\\\":{\\\"state\\\":0}}}\"}}";);
Or alternatively using a raw string literal:
http.POST(R"({"method":"passthrough","params":{"deviceId":"9006765C87CD29BC37447E490C4C91F819143376","requestData":"{\\"system\\":{\\"set_relay_state\\":{\\"state\\":0}}}"}})");

Related

How to add JSON from "Body" in the query parameter?

I'm trying to send a message to an SQS queue. I have everything setup correctly.
I'm using a fifo queue, so my post string looks like this:
https://queuename?Action=SendMessage&MessageBody=TEST&MessageGroupId=6&MessageDeduplicationId=6
The above works and the body of the message is TEST, However, I'd like to send data in JSON format
In the body tab, I have my payload formatted in JSON. How do I get that JSON value into the MessageBody field as a variable?
Step 1. Save json in a variable
const body = {
"key": "value"
}
//encoded the special character to make it valid in URL
const payload = encodeURIComponent(JSON.stringify(body))
//Put it in an environment variable
pm.environment.set("payload", payload)
Step 2: Use this var in URL
https://queuename?Action=SendMessage&MessageBody={{payload}}&MessageGroupId=6&MessageDeduplicationId=6

how to create PACT for multipart/form-data uploading cdc test

I`m trying to create cdc test for uploading file verifying. I use DIUS library. I do not find any examples how to work with .withFileUpload() in DIUS. My code for pact is next:
#Pact(provider = PROVIDER, consumer = CONSUMER)
public RequestResponsePact createPact(PactDslWithProvider builder) throws Exception {
DslPart responseBody = new PactDslJsonBody()
.stringType("resource", DESTINATION_FILENAME)
.stringType("requestId", null)
.stringType("code", "201")
.array("response")
.closeArray()
.asBody();
return builder.given("UploadOperation")
.uponReceiving("Upload operation")
.path("/files/upload")
.matchQuery("overwrite", "true")
.matchQuery("destination_filename", DESTINATION_FILENAME)
.withFileUpload("file",
".gitignore",
"multipart/form-data",
new byte[]{11,44,66,123,66}) // some bytes
.willRespondWith()
.status(201)
.body(responseBody)
.toPact();
}
Code for pact creation and verification:
#Test
#PactVerification
public void doTest() throws IOException {
String url = String.format("Http://localhost:%d/files/upload?overwrite=true&destination_filename=%s", PORT, DESTINATION_FILENAME);
// HttpEntity for request
HttpEntity multipart = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.addBinaryBody("file", new byte[]{11,44,66,123,66},
ContentType.create("multipart/form-data"), ".gitignore")
.build();
// I make the request and get an answer
HttpResponse response = Request.Put(url)
.addHeader("Content-Type", "multipart/form-data;
boundary=j72BRjsEynnAqDw43KTlsjxoKWsjdF_tl6N5")
.body(multipart)
.execute()
.returnResponse();
String json = EntityUtils.toString(response.getEntity());
System.out.println("json=" + json);
JSONObject jsonObject = new JSONObject(json);
assertTrue(jsonObject.getString("code").equals("201"));
assertTrue(response.getStatusLine().getStatusCode() == 201);}
but when I run the test i get: json={"error": Missing start boundary}
java.lang.AssertionError: Pact Test function failed with an exception, possibly due to ExpectedButNotReceived(expectedRequests=[ method: PUT
path: /files/upload
query: [destination_filename:[test], overwrite:[true]]
headers: [Content-Type:multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p]
matchers: MatchingRules(rules={query=Category(name=query, matchingRules={overwrite=MatchingRuleGroup(rules=[RegexMatcher(regex=true, example=null)], ruleLogic=AND), destination_filename=MatchingRuleGroup(rules=[RegexMatcher(regex=test, example=null)], ruleLogic=AND)}), header=Category(name=header, matchingRules={Content-Type=MatchingRuleGroup(rules=[RegexMatcher(regex=multipart/form-data;(\s*charset=[^;]*;)?\s*boundary=.*, example=multipart/form-data; boundary=iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p)], ruleLogic=AND)}), path=Category(name=path, matchingRules={})})
generators: Generators(categories={})
body: OptionalBody(state=PRESENT, value=--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p
Content-Disposition: form-data; name="file"; filename=".gitignore"
Content-Type: multipart/form-data
,B{B
--iYxVLiQ0ZrP5g0SUP2pWa-rg20UM4JFe90p--
)])
...
Caused by: org.json.JSONException: JSONObject["code"] not found.
Whats wrong in my code? I suppose something wrong with Content type, with 'boundary' part. But I dont know how to specify arbitrary boundary.
Maybe anybody knows another library where multipart/form-data uploading requests realized.
Thanks.
I found the solution from test example in DIUS library
contentType in .withFileUpload() and accordingly in .addBinaryBody() methods shouldn`t be "multipart/form-data". It may be "form-data" for example.
.addHeader in request method is not necessary because content type was already defined in body.

How do I make a request using HTTP basic authentication with native C++?

I'm trying to use HttpSendRequest in native C++ to send a basic authentication request to a server. Does anyone have any examples on how to accomplish this?
Edit: So far I've tried encoding the username and password as a base 64 string, example, string auth = "myuser:mypassword" then encoded that into base 64 so it returns a string like dXNlcjpwYXNzd29yZA==.
Then I create a new string that prepends basic to the encoded string, string encoded = "Basic " + "dXNlcjpwYXNzd29yZA=="
Then I connect to the server using InternetOpen and HttpOpenRequest as a POST and those pass successfully.
Then I try passing the encoded string I made to the server using HttpSendRequest
if (HttpSendRequest(hRequest, encoded, sizeof(encoded), NULL, 0)) {
return 1;
} else {
return GetLastError();
}
Not sure what exactly is wrong, but it always returns
error code 12150, ERROR_HTTP_HEADER_NOT_FOUND.

How do I get the Content-Encoding in a POCO::Net::HTTPResponse object?

I'm fetching a server page using Poco::Net::HTTPClientSession with an appropriate Poco::Net::HTTPRequest, which works fine. Now I get a response back, and sometimes the returned page will be gzipped.
I need to find out when that is the case, so that I may deflate if necessary. The HTTP header that should indicate this, is Content-Encoding: gzip; but there's no getContentEncoding() method in Poco::Net::HTTPResponse.
Here's a non-working snippet (because there's no resp.getContentEncoding()):
// resp is the Poco::Net::HTTPResponse object,
// sess is the Poco::Net::HTTPClientSession
std::istream &in = sess.receiveResponse(resp);
// Get the server-returned body as a string (potentially deflate)
std::ostringstream serveroutput;
if (resp.getContentEncoding() == "gzip") {
Poco::InflatingInputStream
inflater(in, Poco::InflatingStreamBuf::STREAM_GZIP);
Poco::StreamCopier::copyStream(inflater, serveroutput);
} else
Poco::StreamCopier::copyStream(in, serveroutput);
// Now we can get at the body as a string
std::string txt = serveroutput.str();
Does anyone know how to get at the raw headers, so that I can inspect the header Content-Encoding myself, or of another useful method to determine whether a server response is gzipped?
if the server set the Content-Encoding header
you could get the encoding value like the following.
resp.get("Content-Encoding")

HttpClient and extracting audio from server response

I am using Apache HttpClient to connect to a server for downloading a .wav file. I am using HTTP POST method in my program.
The server correctly responds with the following header and body:
> HTTP/1.1 200 OK\r\n Content-Disposition: attachment;
> filename=saveme1.mp3\r\n Content-Length: 6264\r\n
> Content-Transfer-Encoding: binary\r\n Content-Type: audio/mp3\r\n
How do I now extract the saveme1.mp3 file from the HTTP response? I am using the following code:
ResponseHandler<String> responseHandler = new BasicResponseHandler();
byte[] data = httpclient.execute(httppost, responseHandler).getBytes();
However, I am getting garbage when I am writing the data to a file.
FileOutputStream fileoutputstream = new FileOutputStream(outputFile);
for (int i = 0; i < data.length; i++)
fileoutputstream.write(data[i]);
If you want download mp3 I Think easiest way is :
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
Now you have entity and can call entity.getContent(); This give you you a inputStream , now you can save this stream with every method you want , ofcurse you need mime type and filename to save your file. if you have problem with filename and mime type tell me to add some sample code.
You are getting MIME attachment that you need to parse first. The BasicResponseHandler just return the response string, but you need the body of the attachment that contains the binary of your .mp3. You would need to do the following steps:
Understand the MIME format. You could skim the Wikipedia Entry for gaining quick familiarity
Once you understood, you need to create a MIME Parser. This would basically extract each part of the MIME message especially the body of your attachment. I think there should be something out there that you could reuse. You probably should look MimeMultipart. The only thing that I am not sure about it is whether it handles "binary" encoding in your message.
Create your own extension of ResponseHandler that will utilize the MIME Parser that you have in the previous step