Building SOAP request using libcurl - c

Below is my code for building a SOAP request:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *ch;
CURLcode res;
struct curl_slist *headerlist=NULL;
struct MemoryStruct *bodyStruct=NULL;
char _gatineauSoapReq[2000]="";
const char *WriteMemoryCallback;
/* Minimalistic http request */
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
ch = curl_easy_init();
curl_easy_setopt(ch, CURLOPT_URL, "http://thermo.sdsu.edu/servlet/ThermodynamicProperties/ThermodynamicPropertiesService");
curl_easy_setopt(ch, CURLOPT_POST, 1);
curl_easy_setopt(ch, CURLOPT_HEADER, 1);
curl_easy_setopt(ch, CURLOPT_VERBOSE, 1);
curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
if ((bodyStruct = (struct MemoryStruct *) malloc(sizeof(struct MemoryStruct))) == NULL) exit(1);
curl_easy_setopt(ch, CURLOPT_FILE, bodyStruct);
curl_slist_free_all(headerlist);
headerlist = curl_slist_append(headerlist, "Content-Type: text/xml");
headerlist = curl_slist_append(headerlist, "SOAPAction: \"http://blabla.com/blabla_services/ValidateNow\"");
sprintf(_gatineauSoapReq, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
<S:Body>
<ns2:getSpeciesInformationResponse
xmlns:ns2="http://ThermodynamicProperties/">
<return>
{"Nist":true,"Abinitio":[["3-21G","MP2",""]],"Nasa":true,"Chemkin":true,"Burcat":true}
</return>
</ns2:getSpeciesInformationResponse>
</S:Body>
</S:Envelope>
curl_easy_setopt(ch, CURLOPT_POSTFIELDS, _gatineauSoapReq);
curl_easy_setopt(ch, CURLOPT_HTTPHEADER, headerlist);
curl_easy_perform(ch);
//res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
//res = curl_easy_send(curl,, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
//for(;;)
{
printf("ok1 \n");
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
printf("ok2 \n");
if(CURLE_OK != res)
//break;
printf("Error: %s\n", strerror(res));
//printf("ok3 \n");
//printf("Received %u bytes.\n", iolen);
printf("data %s \n", buf);
}
/* always cleanup */
curl_easy_cleanup(curl);
return 0;
}
Also along with building the SOAP request, how should one send the request, should we use the curl_easy_send().
I am getting the following error:
curls.c: In function âmainâ:
curls.c:57:45: warning: incompatible implicit declaration of built-in function âmallocâ
curls.c:57:59: error: invalid application of âsizeofâ to incomplete type âstruct MemoryStructâ
curls.c:57:91: warning: incompatible implicit declaration of built-in function âexitâ
curls.c:63:72: warning: backslash and newline separated by space
curls.c:64:22: error: expected â)â before âhttpâ
curls.c:69:60: error: invalid suffix "G" on integer constant
curls.c:146:1: error: expected â;â before â}â token

It seems you have syntax mistakes or missing declarations - have a look at the error lines you provide from your log.

Related

operation was aborted by an application callback - libcurl

I have the following libcurl program. When I run the program I get the following error.
Operation was aborted by an application callback
Process finished with exit code 42
My complete program
#include <stdio.h>
#include <curl/curl.h>
#include <cstdint>
#include <malloc.h>
#include <cstring>
#define TIMETYPE double
#define TIMEOPT CURLINFO_TOTAL_TIME
#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 6000
struct myprogress {
TIMETYPE lastruntime;
CURL *curl;
};
struct memoryStruct {
uint8_t* memory;
size_t size;
};
size_t handleData(void* contents, size_t size, size_t nmemb, void* stream) {
size_t realSize = size * nmemb;
struct memoryStruct* mem = static_cast<struct memoryStruct*>(stream);
mem->memory = static_cast<uint8_t*>(realloc(mem->memory, (mem->size + realSize + 1)));
if (mem->memory == nullptr) {
return 0;
}
memcpy(&(mem->memory[mem->size]), contents, realSize);
mem->size += realSize;
mem->memory[mem->size] = 0;
return realSize;
}
static int xferinfo(void *p,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
struct myprogress *myp = (struct myprogress *)p;
CURL *curl = myp->curl;
TIMETYPE curtime = 0;
curl_easy_getinfo(curl, TIMEOPT, &curtime);
myp->lastruntime = curtime;
fprintf(stderr, "TOTAL TIME: %f \r\n", curtime);
fprintf(stderr," DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T
"\r\n", dlnow, dltotal);
if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES)
return 1;
return 0;
}
int main(void)
{
CURL *curl;
CURLcode res = CURLE_OK;
struct myprogress prog;
struct memoryStruct m_chunk;
curl = curl_easy_init();
if(curl) {
prog.lastruntime = 0;
prog.curl = curl;
m_chunk.memory = static_cast<uint8_t*>(malloc(1));
if (nullptr == m_chunk.memory) {
return 1;
}
m_chunk.size = 0;
curl_easy_setopt(curl, CURLOPT_URL, "http://172.16.132.84:5000/download/file.out");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, handleData);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void*) &m_chunk);
curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo);
curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog);
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
fprintf(stderr, "%s\n", curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
return (int)res;
}
Your file is larger then 6000 bytes:
STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 6000
In this case you return 1 in your xferinfo function, which aborts the download.
Documentation
If your callback function returns CURL_PROGRESSFUNC_CONTINUE it will cause libcurl to continue executing the default progress function.
Returning any other non-zero value from this callback will cause libcurl to abort the transfer and return CURLE_ABORTED_BY_CALLBACK.
see https://curl.haxx.se/libcurl/c/CURLOPT_XFERINFOFUNCTION.html
Test
If I download a file with your code with 4431 bytes I get in the debug console:
...
TOTAL TIME: 0.088631
DOWN: 4431 of 4431
Process finished with exit code 0
If I change STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES to 2000 then I get:
...
Operation was aborted by an application callback
Process finished with exit code 42

ClamAV: Can't allocate memory

I am writing a function in C and it'll work on Debian 8. What the function does is just downloading a file and scanning it by using cURL and ClamAV. So, there are two functions I wrote url2file() and clamav_scan(). And I want to insert url2file() into clamav_scan(). But, it'll show an error message 'Can't allocate memory'... why? If I delete a line url2file() in clamav_scan(), it works very well.
This below is my code I've written.
Thank you.
// this function scans a file by using ClamAV
int clamav_scan(const char* file_name)
{
int ret = 0;
struct cl_engine* engine = NULL; // clamAV engine
unsigned int signo = 0; // clamAV signature number
const char* path = NULL; // clamAV DB path
const char* virname = NULL; // virus name
unsigned long int scanned = 0; // size of scanned data
char target[MAX_PATH] = "./"; // path of the scan file
strcat(target, file_name);
if ((ret = cl_init(CL_INIT_DEFAULT)) != CL_SUCCESS) {
printf("cl_init() failed: %s\n", cl_strerror(ret));
exit(1);
}
if ((engine = cl_engine_new()) == NULL) {
printf("cl_engine_new() failed\n");
exit(1);
}
if ((path = cl_retdbdir()) == NULL) {
printf("cl_retdbdir() failed\n");
cl_engine_free(engine);
exit(1);
}
if ((ret = cl_load(path, engine, &signo, CL_DB_STDOPT)) != CL_SUCCESS) {
printf("cl_load() failed: %s\n", cl_strerror(ret));
cl_engine_free(engine);
exit(1);
}
if ((ret = cl_engine_compile(engine)) != CL_SUCCESS) {
printf("cl_engine_compile() failed: %s\n", cl_strerror(ret));
cl_engine_free(engine);
exit(1);
}
// this is the inserted function I said
// this function downloads a file by using cURL
url2file(url, file_name);
printf("Scanning %s ...\n", target);
if ((ret = cl_scanfile((const char*)target, &virname, &scanned, engine, CL_SCAN_STDOPT)) == CL_VIRUS) {
printf("Virus detected: %s\n", virname);
}
else {
printf("No virus detected\n");
if (ret != CL_CLEAN)
printf("Error: %s\n", cl_strerror(ret)); // shows message here
}
printf("scanned: %lu\n", scanned);
cl_engine_free(engine);
return EXIT_SUCCESS;
}
I referred to
https://curl.haxx.se/libcurl/c/url2file.html
https://raw.githubusercontent.com/vrtadmin/clamav-faq/master/manual/clamdoc.pdf
.
.
.
+++ added url2file() function
static size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream)
{
size_t written = fwrite(ptr, size, nmemb, (FILE*)stream);
return written;
}
int url2file(const char* url, const char* pagefilename)
{
CURL *curl_handle;
FILE *pagefile;
curl_global_init(CURL_GLOBAL_ALL);
/* init the curl session */
curl_handle = curl_easy_init();
/* set URL to get here */
curl_easy_setopt(curl_handle, CURLOPT_URL, url);
/* Switch on full protocol/debug output while testing */
curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
/* disable progress meter, set to 0L to enable and disable debug output */
curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L);
/* send all data to this function */
curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
/* open the file */
pagefile = fopen(pagefilename, "wb");
if (pagefile) {
/* write the page body to this file handle */
curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, pagefile);
/* get it! */
curl_easy_perform(curl_handle);
/* close the header file */
fclose(pagefile);
}
/* cleanup curl stuff */
curl_easy_cleanup(curl_handle);
curl_global_cleanup();
return 0;
}

Turning normal socket used by CURL into SSL socket in C

I'm dealing with code written by a 3rd party (which I don't want to radically change as I'll explain) which opens a tcp connection to talk json-rpc with a server. I want to add ssl to this as the server has an ssl port for the same comms. EDIT: I want to avoid using external proxies (like stunnel, which works).
Currently, the socket is opened by socket() and passed to curl via CURLOPT_OPENSOCKETFUNCTION and libcurl is told to stop after connecting (perform no data transfer) via CURLOPT_CONNECT_ONLY.
I tried enabling the SSL options in CURL starting with curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); but they had no effect, i.e. the connection itself succeeded in that the function connect() returned true (CURL was happy) but the data is still being sent unencrypted.
My understanding is: the socket is created externally (and passed to CURL which is told to not handle data transfer) and then written to directly, not via CURL or OpenSSL, so nothing actually encrypts the transfer ... despite enabling SSL in CURL.
I also tried to point CURL to https:// by doing sprintf(sctx->curl_url, "https%s", strstr(url, "://")); and then I get:
SSL: couldn't create a context: error:140A90A1:lib(20):func(169):reason(161)
I've also tried using OpenSSL directly on the opened socket, like here https://stackoverflow.com/a/41321247/1676217, by initializing OpenSSL and setting its file descriptor to sctx->sock which is the same socket passed to CURL (i.e. calling SSL_set_fd(ssl, sctx->sock);) but SSL_Connect() fails.
I can't change the code entirely to remove CURL or to remove the external socket creation as both are used in other parts of the code, though I can attempt to adapt it.
Basically, I'd like to keep the function declarations for thread_recv_line() and thread_send_line() and make them use SSL.
If anyone proficient with OpenSSL, CURL and/or sockets could show me how to do it within this code snippet, I'd be very grateful.
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#define socket_blocks() (errno == EAGAIN || errno == EWOULDBLOCK)
#define RBUFSIZE 2048
#define RECVSIZE (RBUFSIZE - 4)
struct ctx {
char *url;
CURL *curl;
char *curl_url;
char curl_err_str[CURL_ERROR_SIZE];
curl_socket_t sock;
size_t sockbuf_size;
char *sockbuf;
pthread_mutex_t sock_lock;
};
static curl_socket_t opensocket_grab_cb(void *clientp, curlsocktype purpose,
struct curl_sockaddr *addr)
{
curl_socket_t *sock = (curl_socket_t*) clientp;
*sock = socket(addr->family, addr->socktype, addr->protocol);
return *sock;
}
bool connect(struct ctx *sctx, const char *url)
{
CURL *curl;
int rc;
pthread_mutex_lock(&sctx->sock_lock);
if (sctx->curl)
curl_easy_cleanup(sctx->curl);
sctx->curl = curl_easy_init();
if (!sctx->curl) {
pthread_mutex_unlock(&sctx->sock_lock);
return false;
}
curl = sctx->curl;
if (!sctx->sockbuf) {
sctx->sockbuf = (char*) calloc(RBUFSIZE, 1);
sctx->sockbuf_size = RBUFSIZE;
}
sctx->sockbuf[0] = '\0';
pthread_mutex_unlock(&sctx->sock_lock);
if (url != sctx->url) {
free(sctx->url);
sctx->url = strdup(url);
}
free(sctx->curl_url);
sctx->curl_url = (char*) malloc(strlen(url));
sprintf(sctx->curl_url, "http%s", strstr(url, "://"));
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, sctx->curl_url);
curl_easy_setopt(curl, CURLOPT_FRESH_CONNECT, 1);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, sctx->curl_err_str);
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1);
curl_easy_setopt(curl, CURLOPT_TCP_NODELAY, 1);
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_easy_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockopt_keepalive_cb);
curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, opensocket_grab_cb);
curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, &sctx->sock);
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1);
rc = curl_easy_perform(curl);
if (rc) {
curl_easy_cleanup(curl);
sctx->curl = NULL;
return false;
}
return true;
}
static bool send_line(curl_socket_t sock, char *s)
{
size_t sent = 0;
int len = (int) strlen(s);
s[len++] = '\n';
while (len > 0) {
struct timeval timeout = {0, 0};
int n;
fd_set wd;
FD_ZERO(&wd);
FD_SET(sock, &wd);
if (select((int) (sock + 1), NULL, &wd, NULL, &timeout) < 1)
return false;
n = send(sock, s + sent, len, 0);
if (n < 0) {
if (!socket_blocks())
return false;
n = 0;
}
sent += n;
len -= n;
}
return true;
}
bool thread_send_line(struct ctx *sctx, char *s)
{
bool ret = false;
pthread_mutex_lock(&sctx->sock_lock);
ret = send_line(sctx->sock, s);
pthread_mutex_unlock(&sctx->sock_lock);
return ret;
}
static bool socket_full(curl_socket_t sock, int timeout)
{
struct timeval tv;
fd_set rd;
FD_ZERO(&rd);
FD_SET(sock, &rd);
tv.tv_sec = timeout;
tv.tv_usec = 0;
if (select((int)(sock + 1), &rd, NULL, NULL, &tv) > 0)
return true;
return false;
}
static void buffer_append(struct ctx *sctx, const char *s)
{
size_t old, n;
old = strlen(sctx->sockbuf);
n = old + strlen(s) + 1;
if (n >= sctx->sockbuf_size) {
sctx->sockbuf_size = n + (RBUFSIZE - (n % RBUFSIZE));
sctx->sockbuf = (char*) realloc(sctx->sockbuf, sctx->sockbuf_size);
}
strcpy(sctx->sockbuf + old, s);
}
char *thread_recv_line(struct ctx *sctx)
{
ssize_t len, buflen;
char *tok, *sret = NULL;
if (!strstr(sctx->sockbuf, "\n")) {
bool ret = true;
time_t rstart;
time(&rstart);
if (!socket_full(sctx->sock, 60))
return sret;
do {
char s[RBUFSIZE];
ssize_t n;
memset(s, 0, RBUFSIZE);
n = recv(sctx->sock, s, RECVSIZE, 0);
if (!n) {
ret = false;
break;
}
if (n < 0) {
if (!socket_blocks() || !socket_full(sctx->sock, 1)) {
ret = false;
break;
}
} else
buffer_append(sctx, s);
} while (time(NULL) - rstart < 60 && !strstr(sctx->sockbuf, "\n"));
if (!ret)
return sret;
}
buflen = (ssize_t) strlen(sctx->sockbuf);
tok = strtok(sctx->sockbuf, "\n");
if (!tok)
return sret;
sret = strdup(tok);
len = (ssize_t) strlen(sret);
if (buflen > len + 1)
memmove(sctx->sockbuf, sctx->sockbuf + len + 1, buflen - len + 1);
else
sctx->sockbuf[0] = '\0';
}
This is not what you asked for, but you should consider placing a separate TCP-to-TLS proxy (such as HAProxy) between your code and remote server.
You will have to neither mess with TLS protocol details, nor modify existing code. Such setup will likely be safer and faster than anything you could write yourself.
Libcurl establishes an SSL connection with the server, even with CURLOPT_CONNECT_ONLY. It is not possible to establish another SSL connection on top of the same TCP connection. The only way to continue is to use the same SSL connection that libcurl has already established.
Fortunately it is possible to retrieve the SSL connection data from the curl handle using curl_easy_getinfo and CURLINFO_TLS_SSL_PTR. It should return a pointer of type SSL*.
The thread_send_line and thread_recv_line functions should not use the socket directly, but call SSL_read and SSL_write on the retrieved SSL pointer instead.
See CURLINFO_TLS_SSL_PTR for more information. Make sure you are getting an SSL pointer and not an SSL_CTX pointer.
Something like this should work:
bool thread_send_line(struct ctx *sctx, char *s)
{
bool ret = false;
struct curl_tlssessioninfo* session;
curl_easy_getinfo (sctx->curl, CURLINFO_TLS_SSL_PTR, &session);
SSL* ssl = session->internals;
pthread_mutex_lock(&sctx->sock_lock);
int len = (int) strlen(s);
s[len++] = '\n';
ret = SSL_write(ssl, s, len);
pthread_mutex_unlock(&sctx->sock_lock);
return ret == len;
}

How can I recieve a JSON object from a CURL request in C?

I did this in PHP, and it was relatively easy. However, Its trickier in C, mostly because the cURL library is more tricky, and C isn't object oriented. Here is the snippet of code I have so far:
#include <curl/curl.h>
/* Make first curl call */
curl_global_init();
//initialize first curl instance
CURL *handle;
CURLcode response;
handle = curl_easy_init();
//craft url
char *url = "https://example.com/";
//set url
curl_easy_setopt(handle, CURLOPT_URL, url);
//get resonse
response = curl_easy_perform(handle);
//clean up
curl_easy_cleanup(handle);
The curl should be using get, and also shouldn't I specify Accept: application/json in one of the curlopts?
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
size_t len;
void* buf;
} Body;
typedef size_t (*WriteFunction)(void*, size_t, size_t, void*);
static size_t write_body(const void* ptr, size_t size, size_t nmemb, Body* body_ptr) {
size_t new_len = body_ptr->len + ( size * nmemb );
if (new_len == 0)
return 0;
char* new_buf = realloc(body_ptr->buf, new_len);
if (new_buf == NULL)
return 0;
memcpy(((char*)body_ptr) + new_len, ptr, ( size * nmemb ));
body_ptr->len = new_len;
body_ptr->buf = new_buf;
}
static int write_all(int fd, void* buf, size_t remaining) {
while (remaining > 0) {
ssize_t written = write(STDOUT, buf, remaining);
if (written == -1)
return 0;
remaning -= written;
buf = ((char*)buf) + written;
}
return 1;
}
int main(void) {
CURL* curl = NULL;
struct curl_slist* header_list = NULL;
Body body = { 0, NULL };
int error = 1;
curl = curl_easy_init();
if (curl != NULL) {
fprintf(stderr, "curl_easy_init() failed\n");
goto ERROR;
}
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com/");
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
header_list = curl_slist_append(header_list, "Accept: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header_list);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, (WriteFunction)write_body);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &body);
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
goto ERROR;
}
long http_code;
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
if (http_code < 200 || http_code >= 300) {
fprintf(stderr, "Request not successful: HTTP error code %ld\n", http_code);
goto ERROR;
}
if (body.len == 0) {
printf("Empty response\n");
} else {
printf("Received %zu bytes\n", body.len);
fflush(stdout);
if (!write_all(STDOUT, body->buf, body->len)) {
perror("write");
goto ERROR;
}
}
error = 0;
ERROR:
if ( body.buf != NULL ) free(body.buf);
if ( header_list != NULL ) curl_slist_free_all(header_list);
if ( curl != NULL ) curl_easy_cleanup(curl);
return error;
}
Not tested.

Json string in libcurl

Can I send a Json string using libcurl. I am new to both. Any kind of help would be appreciated. Basically i want to send a Json string using libcurl simple send and receive in C
My code is below:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
const char *request = "reactantsJSON={"O=O":{"N":1}}&productsJSON=["O=O","[O]"]&temperature=2273.15&pressure=101.325";
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://gibbs.sdsu.edu:8080/axis2/services/GibbsMinimization/solveTP");
/* Do not do the transfer - only connect to host */
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
res = curl_easy_perform(curl);
if(CURLE_OK != res)
{
printf("Error: %s\n", strerror(res));
return 1;
}
/* Extract the socket from the curl handle - we'll need it for waiting.
* Note that this API takes a pointer to a 'long' while we use
* curl_socket_t for sockets otherwise.
*/
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* wait for the socket to become ready for sending */
if(!wait_on_socket(sockfd, 0, 60000L))
{
printf("Error: timeout.\n");
return 1;
}
puts("Sending request.");
/* Send the request. Real applications should check the iolen
* to see if all the request has been sent */
res = curl_easy_send(curl, request, strlen(request), &iolen);
if(CURLE_OK != res)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
/* read the response */
for(;;)
{
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 1024, &iolen);
if(CURLE_OK != res)
break;
printf("Received %u bytes.\n", iolen);
}
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
the error I am getting is that it says a ";" is missing in line 40, which is nothing but the json string, even though I ahve a ";" on that line. It looks like to send json string i need to do something, which I am not aware of. Do I need to specify some flags while compiling the code.
const char *request = "reactantsJSON={"O=O":{"N":1}}&productsJSON=["O=O","[O]"]&temperature=2273.15&pressure=101.325";
You need to escape " in your string literal.
const char *request = "reactantsJSON={\"O=O\":{\"N\":1}}&productsJSON=[\"O=O\",\"[O]\"]&temperature=2273.15&pressure=101.325";

Resources