POST JSON to url using CURL and C - c

I'm tring to POST JSON data to a url from bash using:
$ curl -v -d '{xxx:200}&apikey=xxxxx' -X POST http://localhost/xxxx/input/post.json -H "Accept: application/json" -H "Content-Type:application/json"
And in C using the following:
int main(void)
{
CURL *easyhandle;
curl_global_init(CURL_GLOBAL_ALL);
easyhandle = curl_easy_init();
if(easyhandle) {
char *data="json={xxx:200}&apikey=xxxxx";
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://localhost/xxxx/input/post.json");
curl_easy_perform(easyhandle);
curl_easy_cleanup (easyhandle);
}
curl_global_cleanup();
return 0;
}
This is what i'm trying to achieve actually:
http://localhost/xxxx/input/post.json?json={xxx:200}&apikey=xxxxx
It doesn't seem to work. :(
I'm a complete novice to curl. Please help.
Thanks!

Fortunately the server I was sending the data handled POST and GET requests, so the code in question would suffice.
Others with a similar problem can use a simple workaround (If your code doesn't have real time constraints and is not performance intensive). You may fork a bash process using system() from C. This avoids you the trouble of encoding.

What you are trying to do is not performing a POST request but performing a GET request. However, I'm not sure this is a good idea, since GET parameters are limited in length (to something like 2 kB or so), and - as others have already mentioned - they need to be encoded and decoded and all the funky stuff which is a pain in the neck.
The URL pointing to localhost suggests me that you have control over the server code. If you used the POST parameters instead of the GET ones, you could use your current code as-is (which sets the POST body of the request, which is probably the right thing to do -- so you don't have to change your client code, you only have to change the server code.)

Related

Slack - How to upload a file with a mode other than snippet through API

I am attempting to load files to a slack channel automatically from a server via the API, but I'm running up against the 1MB limit for snippets. Is there a way to use file.upload to post files as either hosted or post?
Here's the curl command I'm testing with:
curl -F file=$FILE_PATH -F channels=$CHANNEL_ID \
-F token=$TOKEN -F filename=$SLACK_FILE_NAME \
$SLACK ADDRESS -x $PROXY_SERVER
This successfully posts the file to the channel, but the mode is snippet which means it's not a particularly elegant looking interface in slack and subject to the very small 1MB limit.
EDIT:
When posting the file through the API here is the response that I am getting back (with potentially sensitive information sanitized):
{"ok":true,
"file":{"id":ID_NBR,
"created":1529417913,
"timestamp":1529417913,
"name":FILE_NAME,
"title":FILE_TITLE,
"mimetype":"text\/csv",
"filetype":"csv",
"pretty_type":"CSV",
"user":USER_ID,
"editable":true,
"size":74810,
"mode":"snippet", ###### This is where I see the mode snippet through APIs, in channel it appears as a snippet as well ######
"is_external":false,
"external_type":"",
"is_public":true,
"public_url_shared":false,
"display_as_bot":false,"username":"",
"url_private":URL,
"url_private_download":URL,
"permalink":URL,
"permalink_public":URL,
"edit_link":URL,
"preview":FILE_DATA,
"preview_highlight":"<div class=\"CodeMirror cm-s-default CodeMirrorServer\" oncopy=\"if(event.clipboardData){event.clipboardData.setData('text\/plain',window.getSelection().toString().replace(\/\\u200b\/g,''));event.preventDefault();event.stopPropagation();}\">\n<div class=\"CodeMirror-code\">\n<div><pre>FILE_DATA<\/pre><\/div>\n<\/div>\n<\/div>\n",
"lines":202,
"lines_more":201,
"preview_is_truncated":true,
"channels":[CHANNEL_IDS],
"groups":[],
"ims":[],
"comments_count":0}}

Specify Content Type For Each Part Of A Multipart Form Request

I would like to be able to specify the content type for each part of a multipart form request individually, as specified by RFC 2388 section 3. (https://www.ietf.org/rfc/rfc2388.txt)
For example, in cURL, one can invoke the command
curl -v -X POST http://myserver.com/v1/form-data
-F 'request={"hello":"world"};type=application/json'
It was noted last year that many people have requested this, and the feature would be considered for implementation in a future release:
https://stackoverflow.com/a/38529839/4521962
Please reconsider this feature request, as it is a requirement for a number of contemporary REST API's.

Libcurl with digest authorization in C: send http requests periodically

I'm developing a system that tracks objects with a P(an)T(ilt)Z(oom) camera which can be controlled via HTTP requests. The C application I develop is supposed to receive position data of the tracked object and to send commands to the camera to control the pan and tilt angle. In addition to these commands the camera has to receive a session refresh command every 5 seconds. HTTP Digest Authorization has to be used for the connection.
I'm sending the HTTP request with libcurl. I figured already out that for digest auth one needs to use on and the same curl handle for all requests in this stackoverflow post.
For sending the session refresh command periodically I tried to use a thread which is just doing this:
while(1)
{
usleep(5000000);
sessionContinue(g_Config.cam_ip);
}
With sessionContinue looking like this:
CURLcode sessionContinue(char* url)
{
CURLcode res;
char requestURL[40];
char referer[47];
struct curl_slist *headers=NULL;
strcpy(requestURL , url);
strcat(requestURL, CAM_SESSION_CONTINUE);
strcpy(referer , "Referer: http://");
strcat(referer , url);
strcat(referer , CAM_MONITOR);
headers = curl_slist_append(headers,"Connection:keep-alive");
headers = curl_slist_append(headers, camCookie);
// In windows, this will init the winsock stuff
curl_global_init(CURL_GLOBAL_ALL);
curl_easy_reset(curl);
if(curl)
{
// First set the URL that is about to receive our POST. This URL can
//just as well be a https:// URL if that is what should receive the
//data.
curl_easy_setopt( curl , CURLOPT_URL , requestURL );
curl_easy_setopt( curl , CURLOPT_HTTPHEADER , headers );
curl_easy_setopt( curl , CURLOPT_HTTPGET , 1 );
curl_easy_setopt( curl , CURLOPT_USERNAME , "root" );
curl_easy_setopt( curl , CURLOPT_PASSWORD , "password" );
curl_easy_setopt( curl , CURLOPT_HTTPAUTH , CURLAUTH_BASIC | CURLAUTH_DIGEST );
// Perform the request, res will get the return code
res = curl_easy_perform(curl);
// Check for errors
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed # %s:%d : %s\n", curl_easy_strerror(res) , __FILE__ , __LINE__ );
}
return res;
}
The application always crashed with segmentation fault after executing curl_easy_perform(curl). So I read the libcurl tutorial again and now I know that using one curl handle in multiple threads is a no go.
What I tried then was to use a timer with SIGALRM to implement the periodic session refresh. This didn't change the problem with the crash at curl_easy_perform(curl). The strange thing is that the application doesn't crash when sending the normal command to control the pan and tilt position which uses the same curl handle. The only difference between session refresh and pan/tilt command is that session refresh uses GET and pan/tilt uses POST.
Are there any other possibilities to send pan/tilt commands continuously with a short pause every 5 seconds used to send the session refresh?
You have a long range of problems in one small program. Here's a few:
You might overflow one of those small fixed-size buffers with the dangerous unbounded C functions you use. Quite likely one of them is the reason for the segfault.
curl_global_init() is documented to be called once, you call it over and over again - this even without calling curl_global_cleanup() in between. You obviously call curl_easy_init() somewhere out of the function and you should move the global init there.
'referer' gets filled with data but is never used otherwise
Another advice is to use CURLOPT_ERRORBUFFER to get error messages in rather than curl_easy_strerror() as you may get some extra details then. And of course to set CURLOPT_VERBOSE while debugging the request to see that things look the way you want it.
Thanks for your comment Daniel Stenberg. I'm now calling curl_global_init() just once when the handle has been set up. referer wasn't really needed here, but I had forgotten to remove it before pasting the code here.
The reason for the segmentation fault was that the session refresh command and the commands for pan and tilt tried to use one and the same curl handle at the same time, which obviously can't really work. So the solution with the timer and SIGALRM wasn't the problem. The segmentation faults have been solved by adding a mutex lock to avoid concurrent accesses to the curl handle.

Does the libcurl library give any way to determine which response header came from which command?

Background:
I'm working on my first C program with the library and I need to gather responses from each command sent to a SMTP server.
I've gotten as far as sending commands to the SMTP server and printing the response headers using curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, parse_head), but I'm using multi threaded options. It is not at all clear when I get a response which command it was caused by. I am assuming that they will not necessarily be received in the same order sent. Is that correct?
Making it more difficult, since the library handles some calls (like setting up the initial connection) without my explicit request, I would need to handle more headers than explicit requests. That would be predictable and repeatable, but definitely adds an extra level of complexity.
Question:
Is there a "good" way to determine exactly which command resulted in which response header using multi thread?
Also, moderately related, does the library support returning the numeric return code or do I have to manually parse that out? Looking through the library, it seems that it doesn't. I just want to be sure.
I am assuming that they will not necessarily be received in the same order sent. Is that correct?
Yes, it is. That's how multithreading works.
Is there a "good" way to determine exactly which command resulted in which response header using multi thread?
Yes. You can set user data (context info, whatever you call it) using the CURLOPT_HEADERDATA option - this will be passed in as the 4th argument of your header function. So you can write code like this:
CURL *hndl = curl_easy_init();
// ...
curl_easy_setopt(hndl, CURLOPT_HEADERFUNCTION, parse_head);
curl_easy_setopt(hndl, CURLOPT_HEADERDATA, some_pointer_that_identifies_the_thread);
// ...
size_t parse_head(void *buf, void *size_t sz, size_t nmemb, void *context)
{
// context will be the pointer identifying the thread
}
does the library support returning the numeric return code or do I have to manually parse that out?
Yes, it does:
long httpStatus;
curl_easy_getinfo(hndl, CURLINFO_RESPONSE_CODE, &httpStatus);
if (200 <= httpStatus && httpStatus < 300) {
// HTTP 2XX OK
} else {
// Error (4XX, 5XX) or redirect (3XX)
}

C program to convert Dollar to Rupee

Is there a way to write a C program to convert say Dollar to Indian Rupee (or visa-versa). The conversion parameter should not be hard coded but dynamic. More preciously it should get the latest value of Rupee vs Dollar automatically(from Internet) ?
Step 1 would be to get the latest conversion rate. You can use a web-service for that. There are many available. You can try this.
Request:
GET /CurrencyConvertor.asmx/ConversionRate?FromCurrency=INR&ToCurrency=USD HTTP/1.1
Host: www.webservicex.net
Response:
HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Content-Length: length
<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://www.webserviceX.NET/">SOME_RATE_IN_DOUBLE</double>
For sending the request you can make use of cURL.
Once you have the response, just parse it to get the rate. Once you've the rate you can easily write the program to convert.
EDIT:
If using cURL is something you are not comfortable with you can make use of good old system and wget. For this you need to construct the URL first like:
www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromCurrency=INR&ToCurrency=USD
then from the C program you can do:
char cmd[200];
char URL[] = "www.webservicex.net/CurrencyConvertor.asmx/ConversionRate?FromCurrency=INR&ToCurrency=USD";
sprintf(cmd,"wget -O result.html '%s'",URL); // ensure the URL is in quotes.
system(cmd);
After this the conversion rate is in the file result.html as XML. Just open it and parse it.
If you are using windows, you need to install wget for windows if you don't have it. You can get it here.
First, you need to find a server that can provides the conversion rate. After that, you write your program to fetch the rates from that server and use those information further in your program.
This site, http://www.csharphelp.com/2007/01/currency-converter-server-with-c/ although provides a tutorial for C# + Web, it can give you a general technical idea of how to do it.

Resources