send http requests, keep session alive: C/C++ with cURL(axus camera) - c++

Ive a problem and i cant figure at all how i can manage to solve the following problem:
I would like to send multiple http request to an axis camera.
Here's my code:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http:/root:309#IPADDRESS");
/* example.com is redirected, so we tell libcurl to follow redirection */
// curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
res=curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_URL, "http:/IPADDRESS/axis-cgi/com/ptz.cgi?move=left");
/* 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\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
All i want to do in this example, is to keep my session alive after being logged to the IPaddress, and then send the order "move=left" to this very ip address.
When i execute this program, i got those messages:
<HTML>
<HEAD>
<META HTTP-EQUIV="Expires" CONTENT="Tue, 01 Jan 1980 1:00:00 GMT">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Refresh" CONTENT="0; URL=/view/index.shtml">
Your browser has JavaScript turned off.<br>For the user interface to work effectively, you must enable JavaScript in your browser and reload/refresh this page.
</noscript>
</HEAD>
<BODY>
</BODY>
</HTML>
<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>
<BODY><H1>401 Unauthorized</H1>
Your client does not have permission to get URL /axis-cgi/com/ptz.cgi from this server.
</BODY></HTML>
I assume that i wasnt even logged to the ipaddress...
I never really used this kind of method before... Can you help me with this?
Thank you a lot.

You need to add these two options:
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookie.txt");
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie.txt");
From documentation:
CURLOPT_COOKIEFILE
Pass a pointer to a zero terminated string as parameter. It should
contain the name of your file holding cookie data to read. The cookie
data may be in Netscape / Mozilla cookie data format or just regular
HTTP-style headers dumped to a file.
Given an empty or non-existing file or by passing the empty string
(""), this option will enable cookies for this curl handle, making it
understand and parse received cookies and then use matching cookies in
future requests.
If you use this option multiple times, you just add more files to
read. Subsequent files will add more cookies.
CURLOPT_COOKIEJAR
Pass a file name as char *, zero terminated. This will make libcurl
write all internally known cookies to the specified file when
curl_easy_cleanup(3) is called. If no cookies are known, no file will
be created. Specify "-" to instead have the cookies written to stdout.
Using this option also enables cookies for this session, so if you for
example follow a location it will make matching cookies get sent
accordingly.
If the cookie jar file can't be created or written to (when the
curl_easy_cleanup(3) is called), libcurl will not and cannot report an
error for this. Using CURLOPT_VERBOSE or CURLOPT_DEBUGFUNCTION will
get a warning to display, but that is the only visible feedback you
get about this possibly lethal situation
Read more at: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html

Related

Dropbox API Post API gives response Something went wrong

I'm trying to use Dropbox API to get some metadata info of a file inside my dropbox.
Here is my post code
std::ostringstream stream;
curl_slist* headers = NULL;
CURL* curl = curl_easy_init();
char data[50];
snprintf(data, sizeof(data), "{\"path\":\"%s\"}", "/3.png");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.dropboxapi.com/2/files/get_metadata");
headers = curl_slist_append(headers, "Authorization: <MY TOKEN>");
headers = curl_slist_append(headers, "\"Content-Type\":\"application/json\"");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 30L);
/* pass in a pointer to the data - libcurl will not copy */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, R"({"path":"/3.png"})"); //Tried data char array it doesn't work too.
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
return 0;
/* convert stream to string format */
std::string output = stream.str();
curl_easy_cleanup(curl);
It returns HTTP 400 code
Thats the error I get after http post with curllib
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Dropbox</title>
<link href="https://cfl.dropboxstatic.com/static/metaserver/static/css/error.css" rel="stylesheet" type="text/css"/>
<link rel="shortcut icon" href="https://cfl.dropboxstatic.com/static/metaserver/static/images/favicon.ico"/>
</head>
<body>
<div class="figure">
<img src="https://cfl.dropboxstatic.com/static/metaserver/static/images/illustration_catalog/sickbox-illo_m1.png" srcset="https://cfl.dropboxstatic.com/static/metaserver/static/images/illustration_catalog/sickbox-illo_m1#2x.png 2x" alt="Error: 5xx"/>
</div>
<div id="errorbox">
<h1>Error</h1>Something went wrong. Don't worry, your files are still safe and the Dropboxers have been notified. Check out our Help Center and forums for help, or head back to home.
</div>
On PostMan it gives good response but in my C++ code it gives me error as you can see on above
Http web request body should be something like this
{
"path": "/3.png"
}
Here is response that I get from PostMan
{
".tag": "file",
"name": "3.png",
"path_lower": "/3.png",
"path_display": "/3.png",
"id": "id:kVJQZOYYiMsAAAAAAAAABg",
"client_modified": "2023-02-01T18:54:24Z",
"server_modified": "2023-02-01T18:54:24Z",
"rev": "015f3a7fa16a9c100000002912dfcc0",
"size": 5160,
"is_downloadable": true,
"content_hash": "feb3516ea07bab6053eecc7367ee9c282846f7bc17751b2819b85aa0f3ddefb5"
}
This line:
headers = curl_slist_append(headers, "\"Content-Type\":\"application/json\"");
Looks suspicous with all the inlined quotes around it.
Shouldn't it just be:
headers = curl_slist_append(headers, "Content-Type: application/json");
What you should do is get a tool like Fiddler, Charles, or similar HTTP capture proxy tool and compare the request/response sent by your application and compare it to the one sent by Postman. I think you'll see a discrepancy or two if the above doesn't fix it.

How to set mail body as html in curl?

I need to send html table as email body. I just did the below to mention content type as html, but it did not work.
headers = curl_slist_append(headers, "Content-Type: text/html");
/* pass our list of custom made headers */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
I couldn't find an example from the library site.
CURLOPT_HTTPHEADER will not work with any of the SMTP options (CURLOPT_MAIL_FROM, CURLOPT_MAIL_RCPT, CURLOPT_MAIL_AUTH). Instead you need to use CURLOPT_READFUNCTION.
/* Disclaimer: untested code */
char *msg = "To: bob#example.com\r\n"
"From: alice#example.com\r\n"
"Content-Type: text/html; charset=us-ascii\r\n"
"Mime-version: 1.0\r\n"
"\r\n"
"<html><head>\r\n"
"<meta http-equiv=\"Content-Type\" content="text/html; charset=us-ascii\">\r\n"
"</head><body>\r\n"
"<p>Hi Bob</p>\r\n"
"</body></html>\r\n"
size_t callback(char *buffer, size_t size, size_t nitems, void *instream) {
/* you actually need to check that buffer <= size * nitems */
strcat(buffer, msg);
return strlen(buffer);
}
curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback);
curl_easy_perform(curl);
The documentation for CURLOPT_READFUNCTION has more info. Although, if you're already sending plain text emails, you have been there.
The only real "trick" here that is not presented in Sending Mail Through Curl linked by sameerkn is that you simply dump the Content-Type header inside the email buffer. There is no clever header setting like with HTTP.
Also: i'm not sure whether you need a Content-Transfer-Encoding header, i've set the charset above to us-ascii but things like utf-8 might need transfer encoding.
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); will set the HTTP Protocol Header in your request.
The header which you are showing applies to E-Mail Data (Header section).
E-Mail Data Format: (It has 2 sections, Header and Body separated by blank line)
Header: value
Header: value
Content-Type: text/html; charset="UTF-8"
//**********************// << this is a blank line between Header and Body
Body Of Mail
Does your email contains only HTML?
Try adding following header to Email Headers as well: Content-Transfer-Encoding
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="UTF-8"
quoted-printable is an encoding done to your HTML data. You can encode data as base64 as well.
Content-Transfer-Encoding: base64
**EDIT: If you are trying to send mail using curl then please refer
Send Mail Through CURL

how to get only string name with http request

I am writing code for http request to get string message. i somehow successful in it. here is my code for http request via curl.
#include "stdafx.h"
#include <stdio.h>
#include "curl/curl.h"
int main(void)
{
CURL *curl;
CURLcode res;
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
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, "http://192.168.1.7:8080/asigra_1/helloword.jsp");
/* Now specify the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
/* 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\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
system("pause");
return 0;
}
I can get following output for it
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.or
g/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>
</head>
<body>
hello word
</body>
</html>Press any key to continue . . .
This is whole web page i just need "hello world" in my output not whole page info how should i can do it with curl.
Here's some resources that you can pick and select from to craft up your code as you wish:
getinmemory.c shows how you download data directly into a memory buffer of your own.
htmltidy.c shows how you can do another trick and parse the HTML directly at download. This particular example uses LibTidy to do that job but you may of course opt to use something else, parse it yourself.
htmltitle.cpp is a C++ example that uses libxml2 to parse out the <title> of the downloaded page, which also serves as an example of almost what you're asking for.

using libcurl to call Amazon s3 RESTful service

I am writing a piece of c++ code with libcurl to call Amazon s3 RESTful service as follows:
void SampleOfS3Get()
{
//Init curl
curl_global_init(CURL_GLOBAL_ALL);
CURL* curlHandle = curl_easy_init();
//Init var
char* curlErrStr = (char*)malloc(CURL_ERROR_SIZE);
curl_slist* httpHeaders = NULL;
const char* date = getDateForHeader();
httpHeaders = curl_slist_append(httpHeaders, "Host: s3.amazonaws.com");//Set Host
httpHeaders = curl_slist_append(httpHeaders, date);//Set Date
httpHeaders = curl_slist_append(httpHeaders, getAuthorizationForHeader("AKIAISZALBSY-----XGQ","tIzCC----------/Jsn5KqTfuCAWyD1eyeOKStx0",date));//Set authorization
//Execute
if(curlHandle)
{
curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, CURLOPT_STDERR);//Set verbose mode
curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION,1);//Set automaticallly redirection
curl_easy_setopt(curlHandle, CURLOPT_MAXREDIRS,1);//Set max redirection times
curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, curlErrStr);//Set error buffer
curl_easy_setopt(curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);//Set http version 1.1
curl_easy_setopt(curlHandle, CURLOPT_HEADER, httpHeaders);//Set headers
curl_easy_setopt(curlHandle, CURLOPT_URL, "http://s3.amazonaws.com/");//Set URL
CURLcode curlErr = curl_easy_perform(curlHandle);//Perform
if(curlErr)
{
cout<<curl_easy_strerror(curlErr)<<endl;
}
//Output redirection url
if(CURLE_OK == curlErr)
{
char *url;
curlErr = curl_easy_getinfo(curlHandle, CURLINFO_EFFECTIVE_URL, &url);
if((CURLE_OK == curlErr) && url)
cout<<"CURLINFO_EFFECTIVE_URL: "<<url<<endl;
}
/* Clean-up libcurl */
curl_global_cleanup();
}
}
This function calls the "GET SERVICE" to get the list of all buckets for a specified user.But the HTTP response of this HTTP request turns out to be "a temporary redirect to http://aws.amazon.com/s3" with http state code 307.
Then I find it in the official document which implies that caller should handle the redirection himself,so I add CURLOPT_FOLLOWLOCATION attribute as well.Then the result turns out to be a webpage content of amazon s3.
More details:http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html?r=1821
When I use the example accessID and accessKey in the above link,i get the right signature as "Example List All My Buckets" shows.It confused me that the server redirect my request instead of returning the expected all bucket list of my own(using my own accessID and accessKey).
Somebody encounter the similar problem like mine?SOS...
You should really start by reading http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAPI.html first, as your current code contains many issues. Especially make sure you fully understand how Signing and Authenticating REST Requests work.
This small C++ project seems to do cURL based File PUTs to AWS S3.
with CMake, one can generate VC++ Project/solutions and build it into .LIB static library, or, use it as source code, in your VC++ Solution.
I used it in a VC++ 2013 MFC Project.
Hope it helps.
https://github.com/cedricve/AWS-S3-Cpp-REST-API

CURL is not following 301 Redirects, what do I need to do?

I am using the CURL c++ api to get quotes from Yahoo's financial API. The curl api and my code seem to be working fine, however I am getting a "301" redirect message when I tell CURL to visit the url I want. How can I get CURL to follow through to the 301 redirect and get the data I want?
Here is the URL I am using:
http://download.finance.yahoo.com/d/quotes.csv?e=.csv&s=WSF,WSH&f=b2b3s
Here is the response I am getting:
<HEAD><TITLE>Redirect</TITLE></HEAD>
<BODY BGCOLOR="white" FGCOLOR="black">
<FONT FACE="Helvetica,Arial"><B>
"<em>http://download.finance.yahoo.com/d/quotes.csv?e=.csv&s=WSF,WSH,WSM,WSO,WST,WTI,WTM,WTR,WTS,WTU,WTW,WU,WWE,WWW,WX,WXS,WY,WYN,X,XAA,XCJ,XCO,XEC,XEL,XEL-A,XEL-E,XFB,XFD,XFH,XFJ,XFP,XFR,XIN,XJT,XKE,XKK,XKN,XKO,XL,XL-Y,XOM,XRM,XRX,XVF,XVG,Y,YGE,YPF,YSI,YUM,YZC,ZB-A,ZB-B,ZB-C,ZEP,ZF,ZLC,ZMH,ZNH,ZQK,ZTR,ZZ,ZZC&f=b2b3ccd1d2ghjkk2k3l2l3mm2m3m4m5m6m7m8opst7vw</em>".<p></B></FONT>
<!-- default "Redirect" response (301) -->
</BODY>
Here are my CURL init options
CURL *eh = curl_easy_init();
curl_easy_setopt(eh, CURLOPT_WRITEFUNCTION, cb);
curl_easy_setopt(eh, CURLOPT_HEADER, 0L);
curl_easy_setopt(eh, CURLOPT_URL, url);
curl_easy_setopt(eh, CURLOPT_PRIVATE, url);
curl_easy_setopt(eh, CURLOPT_VERBOSE, 0L);
curl_multi_add_handle(cm, eh);
I didn't post my code, as it is all working, I just need the general method of following through woth the 301's with CURL.
In the PHP world, the option is named CURLOPT_FOLLOWLOCATION. I assume the constant names are standardized and come from the same header file, so this should work for you.
curl_easy_setopt(eh, CURLOPT_FOLLOWLOCATION, 1);
(or whatever "boolean true" is in this context.)
Alternatively, when receiving a 30x status code, you can parse the Location header manually for the new address. Obviously though, the "follow location" option is much easier, as it doesn't require a second request.