Sunday, June 21, 2009

Using libcurl with Newspeak FFI (continued)

The previous post presented a small low level interface to libcurl using the Newspeak programming language. In this post I'm going to show the HttpServiceClient class, which was created to give a simple interface to the LibCurlHelper class.

The definition for class looks like this:


Newsqueak2
'LangexplrExperiments'

class HttpServiceClient usingLib: platform withCurlPath: curlLibraryPath = (
"This class is used to access services provided by the HTTP protocol"
|
LibCurlHelper = platform LibCurlHelper.
ByteString = platform ByteString.
platform = platform.
Transcript = platform Transcript .
private curlLibraryPath = curlLibraryPath .
|
)
(

class HttpRequestResult curlErrorCode: curlErrorCode httpResponse: httpResponse data: data= (
...
)
(
...
)

createNewCurlInstance = (
...
)

get: url <String> ^ <HttpRequestResult> = (
...
)

get: url <String> withHeaders: headers <Array> ^ <HttpRequestResult> = (
...
)

private isHttpsUrl: url <String> ^ <Boolean> = (
...
)

postForm: formData <Dictionary> to: url <String> ^ <HttpRequestResult> = (
...
)

) : (
...
)


The get:, get: withHeaders: and postForm: to: methods provide the functionally to do very simple GET and POST requests.

The HttpRequestResult encapsulates the result of calling these methods which has the result of calling libcurl, the HTTP response code and the text of the requested data if successful.

The code for the GET methods looks like this:

get: url <String> ^ <HttpRequestResult> = (
| curl data tmpBuffer bufferLength response|
^ get: url withHeaders: {}.
)


get: url <String> withHeaders: headers <Array> ^ <HttpRequestResult> = (
| curl data tmpBuffer bufferLength curlCallResult response|
data:: ''.
curl:: createNewCurlInstance.
curl writeCallback:
[:args :result|
bufferLength:: ((args datasize) * (args nmemb)).
tmpBuffer:: ByteString new: bufferLength.
args data copyInto: tmpBuffer
from: 1 to: bufferLength
in: (args data) startingAt: 1.
data:: data,tmpBuffer.
result returnInteger: bufferLength.
].

headers size > 0 ifTrue: [curl headers: headers].

(isHttpsUrl: url)
ifTrue: [curl noSslVerification.].
curl url: url.

curlCallResult:: curl performOperation.

response:: curl responseCode.
curl cleanup.
^HttpRequestResult
curlErrorCode: curlCallResult
httpResponse: response
data: data.
)


The code for the POST operation looks like this:


postForm: formData <Dictionary> to: url = (
| curl data tmpBuffer bufferLength curlFormData response curlCallResult|
data:: ''.
curl:: createNewCurlInstance.

curl post: formData.
curl writeCallback:
[:args :result|
bufferLength:: ((args datasize) * (args nmemb)).
tmpBuffer:: ByteString new: bufferLength.
args data copyInto: tmpBuffer
from: 1 to: bufferLength
in: (args data) startingAt: 1.
data:: data,tmpBuffer.
result returnInteger: bufferLength.
].

(isHttpsUrl: url)
ifTrue: [curl noSslVerification.].

curl url: url.
curlCallResult: curl performOperation.

response:: curl responseCode.
curl cleanup.
^HttpRequestResult
curlErrorCode: curlCallResult
httpResponse: response
data: data.
)


Code for this post can be found here.