How to send soap(xml) request using libcurl - c++

I am trying to send a SOAP request in xml format to a SOAP service using libcurl but i am getting error like" 500 internal server error" while posting the request in soap service.
I have tried almost all the approaches available online.
#include <stdio.h>
#include <curl/curl.h>
int main()
{
FILE * wfp = fopen("res.xml", "w+"); //File pointer to write the soap response
if (!wfp) {
perror("Write File Open:");
// exit(0);
}
struct curl_slist *header = NULL;
header = curl_slist_append(header, "Content-type: text/xml; charset=utf-8");
header = curl_slist_append(header, "SOAPAction: http://localhost:62634/Service1.svc");
header = curl_slist_append(header, "Transfer-Encoding: chunked");
header = curl_slist_append(header, "Expect:");
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:62634/Service1.svc");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:AddNumbers=\"http://localhost:62634/Service1.svc\"><soapenv:Header/><soapenv:Body><AddNumbers xmlns=\"http://tempuri.org/\"><number1>4</number1><number2>5</number2></AddNumbers></soapenv:Body></soapenv:Envelope>");
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data); //Gets data to be written to file
curl_easy_setopt(curl, CURLOPT_WRITEDATA, wfp); //Writes result to file
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)-1);
//curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return 1;
}
}

Related

Libcurl post request not working on Windows 7

I am trying to make a simple POST request to my https REST API and receive the response on a Windows 7 operation system. The firewall is deactivated and the certificate is inside the .exe directory.
Here is the code that I am using:
std::string postRequest(std::string json, std::string endpoint,std::string code,std::string patchOrPOST,std::string source)
{
CURL* curl;
CURLcode res;
std::string response;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
std::string authorization = "Authorization: Basic " + code, portApiHttp = "Referer: " + portAPI + "/index.html", origin = "Origin: " + portAPI;//X-Requested-With: XMLHttpRequest
struct curl_slist* headers = NULL;
if (curl) {
headers = curl_slist_append(headers, "Connection: keep-alive");
headers = curl_slist_append(headers, "Content-Length: "+(int)strlen(json.c_str()));
headers = curl_slist_append(headers, authorization.c_str());
headers = curl_slist_append(headers, "Accept: application/json");
headers = curl_slist_append(headers, "Content-Type: application/json");
if (source.size() != 0)
{
headers = curl_slist_append(headers, source.c_str());
}
headers = curl_slist_append(headers, R"(sec-ch-ua: "Chromium";v="91")");
headers = curl_slist_append(headers, "sec-ch-ua-mobile: ?0");
headers = curl_slist_append(headers, "X - Requested - With: XMLHttpRequest");
headers = curl_slist_append(headers, origin.c_str());
headers = curl_slist_append(headers, "Sec-Fetch-Site: same-origin");
headers = curl_slist_append(headers, "Sec-Fetch-Mode: cors");
headers = curl_slist_append(headers, "Sec-Fetch-Dest: empty");
headers = curl_slist_append(headers, portApiHttp.c_str());
headers = curl_slist_append(headers, "Accept-Encoding: gzip, deflate, br");
headers = curl_slist_append(headers, "Accept-Language: en-US,en;q=0.9");
curl_easy_setopt(curl, CURLOPT_URL,endpoint.c_str());
curl_easy_setopt(curl, CURLOPT_CAINFO, "ca-bundle.crt");
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L);
if (patchOrPOST == "PATCH")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
}
else if (patchOrPOST == "PUT")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
}
else if (patchOrPOST == "GET")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
}
else if(patchOrPOST=="DELETE")
{
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
}
//curl_easy_setopt(curl, CURLOPT_PROXY, "127.0.0.1:8888");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json.c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_MAXREDIRS, 5L);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 50L);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
if (patchOrPOST != "GET")
{
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, json.size());
curl_easy_setopt(curl, CURLOPT_POST, 1);
}
res= curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
if (res!= CURLE_OK) {
curl_easy_cleanup(curl);
return "ERROR";
}
res= curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
if (res!= CURLE_OK) {
curl_easy_cleanup(curl);
return "ERROR";
}
res = curl_easy_perform(curl);
long http_code;
/* 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();
return response;
}
Why does this code work on Windows 10, but has SSL issues on Windows 7?
Why does this code work on Windows 10, but has SSL issues on Windows 7?
Most likely, the server is requesting stronger cryptographic suites than what Windows 7 can provide.
I have similar issue with Windows 7 and libcurl. I have found a solution. I was using libcurl with schannel (default for windows when using vcpkg). The problem was solved when I built libcurl with openssl instead.
If you are using vcpkg, you can install libcurl with openssl with this command:
vckpg.exe install curl[openssl]
You can download a precompiled binary from curl site too. I got the hint solve this from this default windows build for curl:
https://github.com/curl/curl-for-win

C++: How can I Send binary data(protobuf data) using HTTP post request through a curl call

I am trying trying to make a POST request on a url with protobuf data. I don't know how/ where to add binary data. Below is my C++ program.
"
void sendContent()
{
using namespace std;
int Error = 0;
//CString str;
CURL* curl;
CURLcode res;
struct curl_slist *headerlist = NULL;
curl_global_init(CURL_GLOBAL_ALL);
curl = curl_easy_init();
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
//Set URL to recevie POST
curl_easy_setopt(curl, CURLOPT_VERBOSE, true);
curl_easy_setopt(curl, CURLOPT_POST, true);
curl_easy_setopt(curl, CURLOPT_HEADER, true);
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
curl_global_cleanup();
}"
You should set the data pointer by curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);. In the meantime, you should set the data size by curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);.
You can find the libcurl post example in there.
And I copy the program below.
#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://postit.example.com/moo.cgi");
/* Now specify the POST data */
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, length_of_data);
/* binary data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
/* 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();
return 0;
}
Fixing your original suggestion would probably make it something like this (based on the simplepost example from the libcurl web site):
#include <curl/curl.h>
int binarypost(char *binaryptr, long binarysize)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct curl_slist *headerlist = NULL;
headerlist = curl_slist_append(headerlist, "Content-Type: application/x-protobuf");
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:9090/info");
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, binaryptr);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, binarysize);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return (int)res;
}

cUrl Problems with uploading files

Using cUrl ( windows ) and was trying to get an upload function to work. However, it just doesnt seem to work. Getting error ERROR_FILE_NOT_PROVIDED from anonfiles
Here is the API = https://anonfiles.com/docs/api
Here is my code:
std::string UploadPicture()
{
CURL *curl;
CURLcode res;
std::string readBuffer;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.anonfiles.com/upload");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "cache-control: no-cache");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "file=test.ini");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
return readBuffer;
}
return "Failed";
}
Any help is welcome. I have tried many other ways as well, but didnt manage to get it right.

How to define metadata with libcurl?

I do following command with curl (the command line tool) to upload a file to google drive:
curl --request POST \
'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart' \
--header 'Authorization: Bearer "..."' \
-F "metadata={name : 'backup.zip'};type=application/json;charset=UTF-8" \
-F "#backup.zip;type=application/zip"
The following programm with libcurl could only use the URL, the header and upload the file using formdata:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
struct curl_slist *chunk= NULL;
chunk= curl_slist_append(chunk, "Authorization: Bearer \"...\"");
curl_slist_append(chunk, "Accept: application/json");
curl_slist_append(chunk, "Content-Type: application/json");
curl_mimepart *part= NULL;
curl_mime_type(part, "application/octet-stream");
struct curl_httppost* formpost = NULL;
struct curl_httppost* lastptr = NULL;
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_FILE, "main.c",
CURLFORM_END);
/* Perform the request, res will get the return code */
//curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/drive/v3/files");
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, part);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
How can I specify the -F "metadata={name : 'backup.zip'};type=application/json;charset=UTF-8" in libcurl?
I tried it with CURLFORM_COPYNAME but this doesn't work.
You are setting the HTTP request's top-level Content-Type header to application/json, which is wrong. It needs to be multipart/related instead, per Google's documentation: Send a multipart upload request.
The command-line you showed is inserting a MIME part of type application/json into the POST form data, but you are not doing the same thing in your code.
Also, you should not be using CURLOPT_MIMEPOST and CURLOPT_HTTPPOST together. Use ONE or the OTHER, not BOTH. CURLOPT_HTTPPOST is deprecated, replaced by CURLOPT_MIMEPOST. And you are not even passing the correct input value to CURLOPT_MIMEPOST anyway. It expects a curl_mime*, not a curl_mimepart*.
Try something more like this instead:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
/* set custom HTTP headers */
struct curl_slist *header = NULL;
// uncomment this if you are not using libcurl 7.61.0 or later...
//
// header = curl_slist_append(header, "Authorization: Bearer \"...\"");
//
header = curl_slist_append(header, "Content-Type: multipart/related");
header = curl_slist_append(header, "Accept: application/json");
/* set MIME post content */
curl_mime *mime = curl_mime_init(curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_name(part, "metadata");
curl_mime_type(part, "application/json;charset=UTF-8");
curl_mime_data(part, "{\"name\" : \"backup.zip\"}", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(mime);
curl_mime_type(part, "application/zip");
curl_mime_filedata(part, "backup.zip");
/* Perform the request, res will get the return code */
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
// comment this out if you are not using libcurl 7.61.0 or later...
//
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "...");
//
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(header);
curl_mime_free(mime);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}
Or maybe this (I'm not sure the correct way to specify the HTTP Content-Type when using a MIME body - documentation and examples are very limited on this topic, most of the examples I found are for SMTP, not HTTP):
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if (curl)
{
/* set custom HTTP headers */
struct curl_slist *header = NULL;
// uncomment this if you are not using libcurl 7.61.0 or later...
//
// header = curl_slist_append(header, "Authorization: Bearer \"...\"");
//
header = curl_slist_append(header, "Accept: application/json");
/* set MIME post content */
curl_mime *mime = curl_mime_init(curl);
curl_mime *rel = curl_mime_init(curl);
curl_mimepart *part = curl_mime_addpart(rel);
curl_mime_name(part, "metadata");
curl_mime_type(part, "application/json;charset=UTF-8");
curl_mime_data(part, "{\"name\" : \"backup.zip\"}", CURL_ZERO_TERMINATED);
part = curl_mime_addpart(rel);
curl_mime_type(part, "application/zip");
curl_mime_filedata(part, "backup.zip");
part = curl_mime_addpart(mime);
curl_mime_type(part, "multipart/related");
curl_mime_subparts(part, rel);
/* Perform the request, res will get the return code */
curl_easy_setopt(curl, CURLOPT_URL, "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart");
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
// comment this out if you are not using libcurl 7.61.0 or later...
//
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BEARER);
curl_easy_setopt(curl, CURLOPT_XOAUTH2_BEARER, "...");
//
res = curl_easy_perform(curl);
/* always cleanup */
curl_slist_free_all(header);
curl_mime_free(mime);
curl_easy_cleanup(curl);
}
curl_global_cleanup();
return 0;
}

Uploading a picture to a Password Protected Directory using libcurl and C++

I'm trying to upload pictures using c++ application with libcurl to my server, the file in my server is a protected directory, I tried everything I know but it didn't work.
struct curl_slist *headerlist = NULL;
const char * Picture = "C:\xxxx";
FILE *fd = fopen(Picture, "rb");
struct stat file_info;
fstat(fileno(fd), &file_info);
headerlist = curl_slist_append(headerlist, "user : xxxx");
headerlist = curl_slist_append(headerlist, "password : xxxxx");
headerlist = curl_slist_append(headerlist, "Content-Type: image/jpeg");
curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_URL, "http://xxxx.000webhostapp.com/Pictures");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)file_info.st_size);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
MessageBox::Show("Picture Failed");
}
curl_easy_cleanup(curl);
curl_global_cleanup();
user and password are not HTTP headers, so you should not be passing them via CURLOPT_HTTPHEADER. Use CURLOPT_USERNAME and CURLOPT_PASSWORD instead. Also look at CURLOPT_HTTPAUTH.
Try this:
curl_global_init(CURL_GLOBAL_ALL);
...
const char *Picture = "C:\\xxxx";
FILE *fd = fopen(Picture, "rb");
if (!fd)
{
MessageBox::Show("Cannot Open Picture File");
}
else
{
struct stat file_info;
fstat(fileno(fd), &file_info);
curl = curl_easy_init();
if (!curl)
{
MessageBox::Show("Cannot Initialize CURL Session");
}
else
{
struct curl_slist *headerlist = curl_slist_append(NULL, "Content-Type: image/jpeg");
curl_easy_setopt(curl, CURLOPT_URL, "http://xxxx.000webhostapp.com/Pictures");
curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxxx");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (curl_off_t)file_info.st_size);
res = curl_easy_perform(curl);
if (res != CURLE_OK)
{
MessageBox::Show("Picture Failed");
}
curl_easy_cleanup(curl);
}
fclose(fd);
}
...
curl_global_cleanup();