11

I have application that received data via HTTP POST requests. I'm trying to use libcurl to open a request to this app, send the data and receive the reply back from the app. This is the code I have so far:

int main(void)
{
    CURL *curl;
    CURLcode res;

    curl = curl_easy_init();
    if(curl) 
    {
        const int timeout = 30000;
        char outputmessage[]="VGhpcyBpcyBqdXN0IGEgbWVzc2FnZSwgaXQncyBub3QgdGhlIHJlYWwgdGhpbmc=";

        curl_easy_setopt(curl, CURLOPT_URL, "https://somehost.com/someapp");
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
        curl_easy_setopt(curl, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.5");
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, outputmessage);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(outputmessage));
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout/1000);

        res = curl_easy_perform(curl);
        if(CURLE_OK != res)
        {
            printf("Error: %s\n", strerror(res));
            return 1;
        }

        // now what?

        // cleanup when done
        curl_easy_cleanup(curl);
    }
    return 0;
}

This essentially connects to the server, I get a OK on the curl_easy_perform(). I can see the connection on Wireshark.

Two questions:

1) Is this the correct way of sending data via a POST, and
2) How do I get the reply from the application.

I thought I need to use curl_easy_recv() but I can't see how. Any sample code is welcome. Thanks.

Mr Aleph
  • 1,887
  • 5
  • 28
  • 44

2 Answers2

5

I think you should also consider adding a handler for the response headers:

cres = curl_easy_setopt( handle, CURLOPT_HEADERFUNCTION, HandleHeader );

It may be that if this is a web service designed for use by an application, its reply is a header-only reply, with no response data. The header would contain data such as:

HTTP/1.1 200 OK ...

Where the main thing you're looking for is the 200 code saying the request was OK.

The functions to handle the data from either header or response should take a void*, and you'll need to null-terminate it if you're using it as a string. For info this is how I handle the incoming data (in this case I only use the return code in my application - the response body just goes to a log file):

static size_t CurlHandleResponse(
  void *Ptr,
  size_t Size,
  size_t NoElements,
  void* Data )
{
  memcpy( &( gData[gDataLen] ), Ptr, (Size * NoElements) );
  gDataLen += (Size * NoElements);
  gData[ gDataLen ] = '\0';
  return (Size * NoElements);
}

...
ConvertUnprintable( gData, PrintStr );
...

Error handling removed for brevity!

asc99c
  • 3,815
  • 3
  • 31
  • 54
  • The data returned by the app is right after the 200 OK. I need to read the header to see if the request went OK, but then the data after it. Any ideas? And not to file but to a char* – Mr Aleph Oct 21 '11 at 18:25
  • For info, it should be a void *ptr, not a char *ptr, but I'll edit my answer with code I'm using to handle the response. – asc99c Oct 21 '11 at 18:59
  • Got it, thanks. Now I need to start parsing all the info. thanks for the help – Mr Aleph Oct 21 '11 at 19:13
1

You don't need to call any receive function. The received response comes back to you when control passes to the write-finished callback. Set up that callback something like this:

curl_res = curl_easy_setopt( handle, CURLOPT_WRITEFUNCTION, RecvResponseCallback );

before calling perform.

Define the callback like this:

size_t
RecvResponseCallback ( char *ptr, size_t size, size_t nmemb, char *data ) {
  // handle received data
  return size * nmemb;
}

The response data is pointed by the data arg (not the ptr arg, which is something else that you will want to look at when you get this working).

When you exit RecvResponseCallback, be sure to return (size_t) size * nmemb

Pete Wilson
  • 8,610
  • 6
  • 39
  • 51
  • any arguments needs to be declared on RecvResponseCallback() – Mr Aleph Oct 21 '11 at 14:33
  • When set that and i call perform I get `Error: Too many open files in system` – Mr Aleph Oct 21 '11 at 14:35
  • What's the system you are running under? I think libcurl has to open another file for the receive socket. So how many files do you have open in your program? – Pete Wilson Oct 21 '11 at 14:45
  • got it. I just needed to add the return to the callback function. In any case, nothing is coming back. I can see the connection to the server and app but nothing is back – Mr Aleph Oct 21 '11 at 14:49
  • Your best bet at this point is to sign up to the libcurl-users mailing list and ask the question there: http://cool.haxx.se/mailman/listinfo/curl-users – Pete Wilson Oct 21 '11 at 14:59
  • Thanks. Already did that, more than a week ago. No replies. I guess no one wants to help. – Mr Aleph Oct 21 '11 at 15:04
  • Do you see data coming back with wireshark? Also: what happens if you try it with http? And with GET instead of POST? – Pete Wilson Oct 21 '11 at 15:08
  • Yes, I can see it on wireshark. I tried with HTTP POST and it's the same. data is always empty on the callback – Mr Aleph Oct 21 '11 at 16:19
  • You mean wireshark shows you the incoming data, but when you get to the callback there's no data there? OK, what are the values of size and nmemb when you enter the callback routine? – Pete Wilson Oct 21 '11 at 17:38
  • OK, if I save the data coming back (as header and body) i can see the data, yet inside the callback function I cannot work with it. How can I save the value coming on `data` to a string? The `char*` in the callback function is essentially useless right now. I tried playing with `CURLOPT_WRITEDATA` but I only messed things up. This is insane, just to get data back from the server is horrendously complicated. Any ideas? I only need the body of the data being sent after the 200 OK header from the server. – Mr Aleph Oct 21 '11 at 18:17