3

I've developed an application that connects to the PayPal API with libcurl, which I use through the OCurl bindings for OCaml from a process running on a Debian server. The code always works when inside the Paypal sandbox (endpoint https://api-3t.sandbox.paypal.com/nvp) but never works when connecting to the actual Paypal servers (endpoint https://api-3t.paypal.com/nvp).

Libcurl always returns CURLE_RECV_ERROR. The general consensus is that this error happens when there is a network problem, so I have investigated that.

I ran the exact same request with the command-line curl tool from the exact same server, using the exact same process uid/gid, and it consistently works. Tracking the transfers with tcpdump does not reveal any significant difference in the structure of transactions made by the working command-line curl and the non-working application, so it all appears as if the HTTP request is successfully performed in both cases. Then again, it's HTTPS, so I cannot be certain.

Here is the OCaml code that performs the request:

let c = new Curl.handle in
let buffer = Buffer.create 1763 in

c # set_url "https://api-3t.paypal.com/nvp" ;
c # set_post true ;
c # set_postfields "SOMEDATA" ;
c # set_postfieldsize (String.length "SOMEDATA") ;
c # set_writefunction (fun x -> Buffer.add_string buffer x ; String.length x) ;
c # perform ;
c # cleanup ;

Buffer.contents buffer

Here is the equivalent curl command line:

curl -X POST https://api-3t.paypal.com/nvp -d SOMEDATA

EDIT: By increasing the libcurl verbosity, I determined that the underlying error is this:

GnuTLS recv error (-9): A TLS packet with unexpected length was received.

What could be the cause of this error? How can I investigate to find out?

EDIT 2: It appears that the difference between command-line and library use is that the command-line version is linked to OpenSSL and the library is linked to GnuTLS.

How do I link both to OpenSSL?

Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
  • OCurl links against whatever libcurl you have installed. It seems to me that your libcurl and curl proper differ in version numbers, configuration and/or origin. Have you tried refreshing/recompiling libcurl? –  Aug 27 '11 at 11:30

2 Answers2

1

First, the key to further debugging those issues is to use curl's debugging facilities, namely the VERBOSE setting (and also, possibly, the DEBUGFUNCTION setting for printing the data your way).

c # set_verbose true ;

This identified the error as being a problem with GnuTLS that is also discussed here, and which is solved by setting SSLVERSION to 3 to force the use of SSLv3.

c # set_sslversion 3 ;
Victor Nicollet
  • 24,361
  • 4
  • 58
  • 89
0

I always call curl#set_postfieldsize to the length of the data passed to curl#set_postfields. My code would be, then:

let make_get url =
  let curl = new Curl.handle in
  curl#set_writefunction String.length; (* ignore result *)
  curl#set_tcpnodelay true;
  curl#set_verbose false;
  curl#set_post false;
  curl#set_url url;
  curl

let make_post url =
  let curl = make_get url in
  curl#set_post true;
  curl#set_httpheader [
  "Content-Type: text/xml; charset=\"UTF-8\"";
  "SOAPAction: \"\"";
  ];
  curl#set_postfields xml;
  curl#set_postfieldsize (String.length xml);
  curl

I hope this helps.