I'm defining a PUT request with a JSON request body using libcurl in C.
This how I'm doing it:
sprintf(jsonObj, "\"name\" : \"%s\", \"age\" : \"%s\"", name, age);
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charset: utf-8");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
res = curl_easy_perform(curl);
The request body is arriving like this:
{ '"name" : "Pedro", "age" : "22"' }
With { ' at the start and ' } at the end.
--- MORE INFO -----
if I declare this code
char* jsonObj = "{ \"name\" : \"Pedro\" , \"age\" : \"22\" }";
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charset: utf-8");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
res = curl_easy_perform(curl);
the server receives this as the request body:
{ '{ "name" : "Pedro" , "age" : "22" }': '' }
My question is:
Is the libCurl pre-formatting/encoding automatically the Json request?
By the way, does the libCurl have some way of encoding a JSON object?
Thanks so much!
The problem may be with the headers. When you are configuring your curl_slist headers I think you should assign the output of curl_slist_append back to headers:
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charset: utf-8");
Firstly, let's note a few things. To start with, Daniel Stenberg is correct (as I'd hope he would be, given that he wrote the code): libcurl does not append any data to your code. I can demonstrate this with this sample program, which is like your example but with some additional setup/teardown code. This is all of the code: there is nothing else present here:
#include <curl/curl.h>
int main (int argc, char *argv[]) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl == NULL) {
return 128;
}
char* jsonObj = "{ \"name\" : \"Pedro\" , \"age\" : \"22\" }";
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charset: utf-8");
curl_easy_setopt(curl, CURLOPT_URL, "http://http2bin.org/put");
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, jsonObj);
curl_easy_setopt(curl, CURLOPT_USERAGENT, "libcrp/0.1");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
return res;
}
Packet capturing the request with Wireshark shows that this emits the following HTTP request:
PUT /put HTTP/1.1
Host: http2bin.org
User-Agent: libcrp/0.1
Accept: */*
Content-Length: 35
Content-Type: application/x-www-form-urlencoded
{ "name" : "Pedro" , "age" : "22" }
As you can see, this is exactly the JSON data you asked to send. There is no extra data here, no enclosing braces.
This means that the extra braces are being added either by your server or by some intermediate middlebox. My guess is that your server is adding it because it is forcibly trying to turn any body that is not an application/json body into one by considering the entire body a string.
The reason your server doesn't consider this a JSON body is encapsulated by another answer here: you aren't setting your headers properly. curl_slist_append returns a new struct curl_slist * that you need to assign back into your headers variable. That means you need to change these four lines:
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Accept: application/json");
curl_slist_append(headers, "Content-Type: application/json");
curl_slist_append(headers, "charset: utf-8");
to these four:
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "charset: utf-8");
This should convince your server that you are sending JSON data.
In the future, I recommend you get familiar with Wireshark for solving problems like this. It is extremely helpful to see the actual request you sent. Failing that, if you'd rather not, you can use CURLOPT_DEBUGFUNCTION to grab the data curl is sending to validate it.
I was having a similar Issue.
I discovered the -libcurl option for the curl command.
It helped a lot! Just add it to the end of your working curl command.
In the end it help me create this code:
CURLcode ret;
CURL *hnd;
struct curl_slist *slist1;
std::string jsonstr = "{\"username\":\"bob\",\"password\":\"12345\"}";
slist1 = NULL;
slist1 = curl_slist_append(slist1, "Content-Type: application/json");
hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_URL, "http://u/r/l");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(hnd, CURLOPT_POSTFIELDS, jsonstr.c_str());
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.38.0");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, slist1);
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
ret = curl_easy_perform(hnd);
curl_easy_cleanup(hnd);
hnd = NULL;
curl_slist_free_all(slist1);
slist1 = NULL;
Express recieves this JSON as:
{ username: 'bob', password: '12345' }
I hope this helps!
libcurl will send exactly the bytes you ask it to send. It has no knowledge of JSON at all.
See #Lukasa's excellent and more elaborate answer for better and more details.
A key part of understanding whether the system is behaving correctly is seeing what the program is actually sending over the network. So another way to check the byte stream, instead of pointing it at your server (and/or running Wireshark), is to just run a netcat instance in a separate window on the test machine:
nc -l 8080
and point the code (CURLOPT_URL) at "http://localhost:8080".
You'll need to hit Control-D in the nc window to terminate the connection so that curl completes, but you can also type a test return text beforehand, which can be useful if you're expecting some sort of reply to test against.
Had this same problem when posting data to node-red with json parser.
Solution for me was to treat string as a HTML
#include <curl/curl.h>
int main (int argc, char *argv[]) {
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
if (curl == NULL) {
return 128;
}
struct curl_slist *headers = NULL;
curl_slist_append(headers, "Content-Type: application/json");
curl_easy_setopt(curl, CURLOPT_URL, #yourURL);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "age=42&sex=male");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
return res;
}
Hope someone will find it helpful.
I used json-c for encoding and decoding jsons and it worked very well.
The documentation is also easy to understand.
https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
Related
I need to send cURL request to an api but i don't understand the documentation properly. First time working with cURL. Here is the details written to send request.
# Steps to send request
# First get JSON Web Token
# Please get your Client Id and Client Secret from https://dashboard.groupdocs.cloud/applications.
# Kindly place Client Id in "client_id" and Client Secret in "client_secret" argument.
curl -v "https://api.groupdocs.cloud/connect/token" \
-X POST \
-d "grant_type#client_credentials&client_id#xxxx&client_secret#xxxx" \
-H "Content-Type: application/x-www-form-urlencoded" \
-H "Accept: application/json"
$ cURL example to join several documents into one
curl -v "https://api.groupdocs.cloud/v1.0/parser/text" \
-X POST \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-H "Authorization: Bearer
<jwt token>" \
-d "{
"FileInfo": {
"FilePath": "words\docx\document.docx",
}
}"
This is how the response will come
{
"text": "First Page\r\r\f"
}
Curl is just a tool for sending requests
you can do the same with http package in flutter
your first request with curl is equivalent to this
var headers = {
'Content-Type': 'application/x-www-form-urlencoded'
};
var request = http.Request('POST', Uri.parse('https://api.groupdocs.cloud/connect/token'));
request.bodyFields = {
'grant_type': '',
'client_id': '',
'client_secret': ''
};
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
second request
var headers = {
'Authorization': 'Bearer <jwt token>',
'Content-Type': 'application/json'
};
var request = http.Request('POST', Uri.parse('https://api.groupdocs.cloud/v1.0/parser/text'));
request.body = json.encode({
"FileInfo": {
"FilePath": "words\\docx\\document.docx"
}
});
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
learn about http request , use a tool like postman to get used to it and then use http to send those requests
I have been reading tutorials for two days and I really cant understand what are my options. I have a machine with HMI that runs web server (I dont know what kind of web server that is). I can acces HMI tags values trought POST request with json data.
The rquest example look like this
$( document ).ready(function() {
var data0 = {"getTags":["Start_dav","CutON","run_rot_actual"],"includeTagMetadata":true};
var json = JSON.stringify(data0 );
$.ajax({
url: "http://ipaddress/tagbatch",
type: "POST",
dataType: "json",
data: json,
The response is json data.
The problem is of course in cross domain policy. I have no control over the machine and there is no option to set up CORS. I have read about proxy, iframe and yql solutions but as I understand I cant send json data with these workarounds. Is there any way how to send post request with json cross domain?
Thank you for you help
I found a solution. I am using php curl for sending a request.
Here is the working code:
$data = array("getTags" => array("Var1","Var2"), "includeTagMetadata" => false);
$data_string = json_encode($data);
$agent= 'Mozilla/5.0 (Windows; U;Windows NT 5.1; ru; rv:1.8.0.9) Gecko/20061206 Firefox/1.5.0.9';
//open connection
$ch = curl_init();
$f = fopen('request.txt', 'w'); //writes headers to this file
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL,"domainipaddress");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch,CURLOPT_POSTFIELDS,$data_string);
$tmpfname = dirname(__FILE__).'/cookie.txt'; //saves the cookie from server
curl_setopt($ch, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($ch, CURLOPT_COOKIEFILE, $tmpfname);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER , false);
curl_setopt($ch, CURLOPT_USERAGENT, $agent);
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_VERBOSE, 1 );
curl_setopt( $ch, CURLOPT_STDERR, $f );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt($ch, CURLOPT_FORBID_REUSE, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen($data_string),
'Connection: keep-alive',
"Keep-Alive: 300"
)
);
//execute post
$result = curl_exec($ch);
$headers = curl_getinfo($ch);
fclose($f);
std::string DownloadFile(std::string Fname, std::string Furl)
{
CURL *curl;
CURLcode res;
const char *url = Furl.c_str();
curl = curl_easy_init();
if (curl) {
FILE * pFile;
pFile = fopen(Fname.c_str(),"wb");
if (pFile!=NULL) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, pFile);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, FALSE);
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_func);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
char errbuf[CURL_ERROR_SIZE];
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
res = curl_easy_perform(curl);
std::string xres = curl_easy_strerror(res);
curl_easy_cleanup(curl);
fclose(pFile);
return xres;
}
}
}
I'm getting this error:
An unhandled exception of type 'System.AccessViolationException'
occurred in Fourth.exe Additional information: Attempted to read or
write protected memory. This is often an indication that other memory
is corrupt.
on the line:
res = curl_easy_perform(curl);
Any ideas where i am going wrong?
It most likely has to do with one of your curl options, I would look at the obvious ones you have added such as CURLOPT_WRITEFUNCTION, CURLOPT_WRITEDATA, or CURLOPT_ERRORBUFFER. My initial comment was wrong :/
Is there actually a required json object which each push service requires. For example I always see the following in every tutorial:
Android:
var notification = "{\"data\":{\"msg\":\"Breaking " + category + " News!\"}}";
Apple:
var alert = "{\"aps\":{\"alert\":\"Breaking " + category + " News!\"}}";
Do these structures have to be kept? or can I send my own custom objects down to the phone?
I think your question is quite specific to certain platform you are trying to send the Push Notification. If you want to just implement the GCM on standard Android Native App.. You can just embed the code in your server implementation.
public function send_notification($registatoin_ids, $message) {
// include config
include_once './config.php';
// Set POST variables
$url = 'https://android.googleapis.com/gcm/send';
$fields = array(
'registration_ids' => $registatoin_ids,
'data' => $message,
);
$headers = array(
'Authorization: key=' . GOOGLE_API_KEY,
'Content-Type: application/json'
);
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// Disabling SSL Certificate support temporarly
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
// Execute post
$result = curl_exec($ch);
if ($result === FALSE) {
die('Curl failed: ' . curl_error($ch));
}
// Close connection
curl_close($ch);
echo $result;
}
So the answer to your question is No.
i have read here, that the Odata Webservice also supports the JSON format. But how can I get that?
When I send a request i only get the following format> application/atom+xml
Try something like that:
$.ajax({
type: "GET",
contentType: "application/json; charset=utf-8",
datatype: "json",
url: odataSelect,
beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Accept", "application/json"); },
success: function (data, textStatus, XmlHttpRequest)
{
ProcessReturnedEntities(data.d.results);
ProcessReturnedEntity(data.d);
},
error: function (XmlHttpRequest, textStatus, errorThrown) { alert('OData Select Failed: ' + odataSelect); }
});
See this site for a complete example.
For WinJS inside Windows 8 apps with HTML & JS its the following:
WinJS.xhr({
type: "GET",
datatype: "json",
url: 'http://localhost:7048/DynamicsNAV70/OData/P_21/',
headers: {
"Content-type": "application/json; charset=utf-8", "Accept": "application/json" },
}).done(function (data, textStatus, XmlHttpRequest) {
console.log();
},
function (err) {
console.log();
});
Please note the different definition of the header. The values are exactly the same.
To communicate with your OData web services using JSON instead of XML, you really only need to set the following two headers :
Accept: application/json
Content-Type: application/json; charset=utf-8
Alternatively, you could also put ?$format=json at the end of your URL.
This it true no matter what programming language you're using to communicate with Microsoft Dynamics NAV. It works the same for JavaScript, JAVA, Python, Ruby, PHP, ...
Demo code
Here's how to do a basic GET request from PHP :
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://<Server>:<WebServicePort>/<ServerInstance>/OData/Company(\'<CompanyName>\')/customer(\'1\')');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, false);
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
]);
$response = json_decode(curl_exec($ch), TRUE);
echo json_encode($response, JSON_PRETTY_PRINT);
// Close handle
curl_close($ch);
Here's how to do a basic POST request from PHP :
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://<Server>:<WebServicePort>/<ServerInstance>/OData/Company(\'<CompanyName>\')/customer');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"Name" => "This is a test customer",
...
]));
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
]);
$response = json_decode(curl_exec($ch), TRUE);
echo json_encode($response, JSON_PRETTY_PRINT);
curl_close($ch);
Here's how to do a basic PATCH request from PHP :
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://<Server>:<WebServicePort>/<ServerInstance>/OData/Company(\'<CompanyName>\')/customer(\'1\')');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PATCH');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"Name" => "This is a test customer",
...
]));
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'If-Match: W/"\'' . $etag . '\'"'
// You can get your etag value by doing a get request first
]);
$response = json_decode(curl_exec($ch), TRUE);
echo json_encode($response, JSON_PRETTY_PRINT);
curl_close($ch);
Here's how to do a basic DELETE request from PHP :
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://<Server>:<WebServicePort>/<ServerInstance>/OData/Company(\'<CompanyName>\')/customer(\'1\')');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_USERPWD, 'username:password');
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Accept: application/json',
'Content-Type: application/json; charset=utf-8',
'If-Match: W/"\'' . $etag . '\'"'
// You can get your etag value by doing a get request first
]);
$response = json_decode(curl_exec($ch), TRUE);
echo json_encode($response, JSON_PRETTY_PRINT);
curl_close($ch);
Note 1
If you need to create / update data, don't forget to Json-encode your POST fields :
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
"Name"=> "This is the name of my new customer"
]));
Using a query string or array instead will generate an error An error occurred while processing this request., which could leave you puzzled for quite a while...
Note 2
For those who don't like working with raw cURL requests, I just uploaded a basic OO wrapper class, which you can find at this gist.