[UFO Chicago] C++ REST SDK (technical, for libcurl programmers only)

jay at m5.chicago.il.us jay at m5.chicago.il.us
Wed Mar 9 20:54:23 PST 2016


Centuries ago, Nostradamus predicted that Brian Sobolak would write on Wed Mar  9 21:53:15 2016:

> 
> On Tue, March 8, 2016 1:50 pm, jay at m5.chicago.il.us wrote:
>>
>> Fellow Nerds,
>>
>> I am writing a C++ program that needs to contact the Stripe server
>> (https://stripe.com/documents/api#intro).  It is a REST interface.
>> The development (and, for the moment, the deployment) platform is
>> Centos 6.6 and the program has to be compiled with the -m32 option
>> because it links with proprietary 32-bit libraries to which we do
>> not have the source.
>>
>> Stripe provides APIs in Ruby, Python, PHP, and Java -- all interpreted
>> languages -- and also documents what it calls its "Curl" API, which
>> means, as I understand it, "here are the URLs, you connect to them
>> and send and retrieve data using any language you like".  This could
>> literally be using the curl program in a shell script, or it could
>> be connecting to the URLs from within a program some other way.
>>
> 
> Also, libcurl...
> 
> https://curl.haxx.se/libcurl/
> 
> brian
> 

Yes, I have started using libcurl, since posting the above.

But I have not been able to get it to work.  I have read the fabulous
manual, and still I have not been able to get it to work.

I need to write a program that accomplishes in C what the following
command line invocation accomplishes:

  curl --trace-ascii - "https://xxxxx:@api.stripe.com/v1/charges" -d "customer=xxx&currency=USD&amount=123"

where the Stripe ID and the Stripe customer ID have obviously been
redacted.

When I run the above program with "--trace-ascii -", I see the
following, in pertinent part:

 POST /v1/charges HTTP/1.1
 Authorization: Basic c2tfdGVzdF9sSzhyQkdHcWFQSDJPZkxqNng0RlM5YTM6
 User-Agent: curl/7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7
  NSS/3.19.1 Basic ECC zlib/1.2.3 libidn/1.18 libssh2/1.4.2
 Host: api.stripe.com
 Accept: */*
 Content-Length: 51
 Content-Type: application/x-www-form-urlencoded
 => Send data, 51 bytes (0x33)
 customer=xxx&currency=USD&amount=123
 <= Recv header, 17 bytes (0x11)
 HTTP/1.1 200 OK
 <= Recv header, 15 bytes (0xf)
 Server: nginx
 <= Recv header, 37 bytes (0x25)
 Date: Thu, 10 Mar 2016 04:05:21 GMT
 <= Recv header, 32 bytes (0x20)

et cetera.  The point is, that curl does the post, then sends the post
data, then receives an OK response, followed by headers and (not shown
above) data.  In other words, the program succeeds.

I have tried to accomplish the same within a C++ program, using
libcurl.  This is, in pertinent part, what I have, which, according to
my reading of the fabulous manual, ought to work:

    curl_global_init(CURL_GLOBAL_ALL);
    CURL *curlhandle = curl_easy_init();

    curl_easy_setopt(curlhandle, CURLOPT_URL, "https://xxxxx:@api.stripe.com/v1/charges");
    std::string postfields = "customer=xxx&currency=USD&amount=123";
    curl_easy_setopt(curlhandle, CURLOPT_POSTFIELDS, postfields.c_str());
    curl_easy_setopt(curlhandle, CURLOPT_POSTFIELDSIZE, (long)postfields.length());
    curl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);

    CURLcode retval = curl_easy_perform(curlhandle);
    curl_easy_cleanup(curlhandle);
    curl_global_cleanup();

(I have not registered a callback function to receive the returned
data; for the moment, I am satisfied to let the returned data be
written to standard output, like the curl program does.)

It does not work.  The curl utility outputs the retrieved data,
whereas my attempt to create the libcurl equivalent, produces a "Bad
Request" error message.  Here it is in detail:

 POST /v1/charges HTTP/1.1
 Authorization: Basic c2tfdGVzdF9sSzhyQkdHcWFQSDJPZkxqNng0RlM5YTM6
 Host: api.stripe.com
 Accept: */*
 Content-Length: 51
 Content-Type: application/x-www-form-urlencoded

 HTTP/1.1 400 Bad Request
 Server: nginx
 Date: Thu, 10 Mar 2016 02:35:47 GMT
 Content-Type: text/plain; charset=utf-8
 Content-Length: 522
 Connection: keep-alive

 (data then follow, containing a JSON representation of the error message)

It does not appear that the POST fields are being sent.  What am I
missing?  What does one do in libcurl that I have not done?

In case you were about to suggest it, I did run ltrace on the
successful curl program, and grep the output for curl_easy.  The
output is not helpful,  I see curl_easy_init() called with 5
arguments, rather than 0, and I see curl_easy_setopt() being called a
hundred times (this may be an exaggeration, but if so, it is only a
slight one) with 5 arguments rather than 3.  But ltrace does not show
me the symbolic constants in the argument list to the curl_easy_*
functions, it does not show me their significance or how they were
computed, it does not tell me how to write my C++ program so that it
does what the curl program does.

As always, thank you in advance for any and all replies.


                        Jay F. Shachter
                        6424 N Whipple St
                        Chicago IL  60645-4111
                                (1-773)7613784   landline
                                (1-410)9964737   GoogleVoice
                                jay at m5.chicago.il.us
                                http://m5.chicago.il.us

                        "Quidquid latine dictum sit, altum videtur"


More information about the ufo mailing list