# What is *curlhs*?
*curlhs* is a [Haskell][haskell.htm] library that provides
a [Haskell][haskell.htm] interface to *libcurl* - the multiprotocol
file transfer library.
> *libcurl* is most probably the most portable, most powerful
> and most often used C-based multi-platform file transfer library
> on this planet - be it open source or commercial.
The main *libcurl* web site is at
and it contains a vast amount of documentation and resources.
It is highly recommended to be familiar with those materials
to comfortably use *curlhs*.
# How to install?
*curlhs* is written in the [Haskell][haskell.htm] programming language
and requires the Haskell compiler [GHC][ghc.htm] and the Haskell's
package manager [Cabal][cabal.htm] to build. The easiest way to get
them is with the [Haskell Platform][platform.htm] binary installer.
If you already have Cabal set up, then getting *curlhs*
should be as simple as running two commands:
```sh
$ cabal update
$ cabal install curlhs
```
This will download and install the latest *curlhs* package from
[Hackage][hackage.htm].
The most recent *curlhs* can be installed from GitHub:
```sh
$ git clone https://github.com/kkardzis/curlhs.git
$ git clone https://github.com/kkardzis/rtld.git
$ cabal update && cabal install ./rtld ./curlhs
```
One way or another, installation should pass without complications.
Tested on Windows, FreeBSD and Linux ([travis-ci][travis.htm]).
# Does it work?
To see if *curlhs* works, let's try to check *libcurl* version. Run GHCi:
```sh
$ ghci
```
The simple call to `curl_version` should return the *libcurl* version string:
```hs
ghci> :m Network.CURL720
ghci> curl_version
*** Exception: failed to call 'curl_version' (NULL)
```
Obviously that's not what was expected. But what's wrong? The short answer
is that *libcurl* was not loaded before use. *curlhs* depends on *libcurl*,
but does not link with *libcurl* at compile/build time like most libraries
would. Instead, it is necessary to explicitly load *libcurl* at runtime.
So let's try:
```hs
ghci> loadlib CURL720
*** Exception: failed to load libcurl/7.20 ["libcurl.dll"]
```
What now? Let's assume we are on Windows, where *libcurl* is not installed
by default. The dynamic loader searchs for "libcurl.dll", but it cannot find
it in the default search path. It's time to install *libcurl*.
# Where is *libcurl*?
### Windows
Using *libcurl* from Haskell was always a pain on Windows. But not anymore.
With *curlhs* it's now easy to use them together. All that *curlhs* needs
to work is a "libcurl.dll" with its dependencies like SSL, SSH etc.
*libcurl* can be build from source of course, but the recommended
way is to search for the precompiled binaries for Windows.
Good place to start may be at .
Be careful. *libcurl* uses many different libraries behind the scenes to do
its work, some (but not all) of which are optional. *libcurl* may be built
with different implementations of SSL for example, or even without SSL
support at all. Similarly, other features may only be available if they
were selected at compile time for *libcurl*, so pay attention to how
a package was build and that all dependencies are included.
A good choice for *libcurl*, although not the latest version, are these
packages from :
*
*
For Win32 for example in 'curl-7.34.0-devel-mingw32\bin\' we have:
* libcurl.dll
* libeay32.dll
* libidn-11.dll
* librtmp.dll
* libssh2.dll
* ssleay32.dll
* zlib1.dll
Where should we put those DLLs? Please refer to the `LoadLibrary` function
documentation on MSDN for exhaustive information about the default
search path used to locate the libraries in Windows. Three notable
places where Windows looks for the DLLs are:
* the directory from which the application was loaded (where the exe is)
* the directories listed in the PATH environment variable
* the current directory
That's it. To test just `cd` to the directory where those DLLs
are placed and run GHCi from there.
### Linux
In the unix world *libcurl* is a widely used library and is probably
installed by default, or as a dependency for some tool, notably the
popular tool *curl*. To check it, use the command `curl --version`.
If *libcurl* has not been installed, the easiest way to install it and its
dependencies is with the system package manager like *apt-get*, *yum*
or similar. For example:
```sh
$ apt-get update
$ apt-get install curl
```
On Linux systems *curlhs* searchs for "libcurl.so.4" or "libcurl.so"
(in that order). Default search path is implementation dependent.
Please refer to the `dlopen` man page for more information.
### BSD
As with Linux systems: first check if *libcurl* is installed,
for example with `curl --version`, and if it's not, use the system package
manager to install it. For example:
```sh
$ pkg update
$ pkg install curl
```
On BSD systems *curlhs* searchs for "libcurl.so". Please refer to
the `dlopen` man page for information about the default search path
used to locate libraries.
### OS X
On OS X system *curlhs* searchs for "libcurl.dylib".
Disclaimer: this platform was not tested, sorry.
# It works? Really?
Now, when *libcurl* is in the scope, let's try again. Let's assume we
are on Windows with "libcurl/7.34" like in the example above. Run GHCi,
import one of the *curlhs* modules, load *libcurl*, and finally check
its version:
```hs
ghci> :m Network.CURL720
ghci> loadlib CURL720
ghci> curl_version
"libcurl/7.34.0 OpenSSL/1.0.0k zlib/1.2.8 libidn/1.18 libssh2/1.4.3 librtmp/2.3"
```
Excellent! But what if...
```hs
ghci> freelib CURL720
ghci> curl_version
*** Exception: failed to call 'curl_version' (NULL)
```
Nice.
# Hello World!
This is about the file transfer library, so let's try to download something:
```hs
ghci> :m Network.CURL720
ghci> loadlib CURL720
ghci> c <- curl_easy_init
ghci> curl_easy_setopt c [CURLOPT_URL "http://httpbin.org/get"]
ghci> curl_easy_perform c
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Host": "httpbin.org",
"X-Request-Id": "00000000-0000-0000-0000-000000000000"
},
"origin": "000.000.000.000",
"url": "http://httpbin.org/get"
}
```
And maybe simple upload:
```hs
ghci> curl_easy_setopt c [CURLOPT_URL "http://httpbin.org/post"]
ghci> curl_easy_setopt c [CURLOPT_COPYPOSTFIELDS "Hello World!"]
ghci> curl_easy_perform c
{
"args": {},
"data": "",
"files": {},
"form": {
"Hello World!": ""
},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Content-Length": "12",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"X-Request-Id": "00000000-0000-0000-0000-000000000000"
},
"json": null,
"origin": "000.000.000.000",
"url": "http://httpbin.org/post"
}
```
# That's all now
I would be grateful for any comments or concerns you may have.
[haskell.htm]: http://www.haskell.org/
[ghc.htm]: http://www.haskell.org/ghc/
[cabal.htm]: http://www.haskell.org/cabal/
[platform.htm]: http://www.haskell.org/platform/
[hackage.htm]: https://hackage.haskell.org/package/curlhs
[travis.htm]: https://travis-ci.org/kkardzis/curlhs
![GA](https://ga-beacon.appspot.com/UA-53767359-1/curlhs/docs/tutorial)