packages feed

curlhs 0.1.1 → 0.1.2

raw patch · 18 files changed

+686/−84 lines, 18 filesdep +curlhsdep +hspecdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: curlhs, hspec

Dependency ranges changed: base

API changes (from Hackage documentation)

- Network.CURLXXX: CURL720 :: LIBCURL
- Network.CURLXXX: CURL730 :: LIBCURL
- Network.CURLXXX: class RTLD so
- Network.CURLXXX: data LIBCURL
- Network.CURLXXX: freelib :: RTLD so => so -> IO ()
- Network.CURLXXX: loadlib :: RTLD so => so -> IO ()
- Network.CURLXXX: withlib :: RTLD so => so -> IO a -> IO a
+ Network.CURL000: CURL720 :: LIBCURL
+ Network.CURL000: CURL730 :: LIBCURL
+ Network.CURL000: class RTLD so
+ Network.CURL000: data LIBCURL
+ Network.CURL000: freelib :: RTLD so => so -> IO ()
+ Network.CURL000: loadlib :: RTLD so => so -> IO ()
+ Network.CURL000: withlib :: RTLD so => so -> IO a -> IO a
- Network.CURL720: CURLOPT_SSL_VERIFYHOST :: CLong -> CURLoption
+ Network.CURL720: CURLOPT_SSL_VERIFYHOST :: Bool -> CURLoption
- Network.CURL730: CURLOPT_SSL_VERIFYHOST :: CLong -> CURLoption
+ Network.CURL730: CURLOPT_SSL_VERIFYHOST :: Bool -> CURLoption

Files

+ Network/CURL000.hs view
@@ -0,0 +1,23 @@+-------------------------------------------------------------------------------+-- |+-- Module      :  Network.CURL000+-- Copyright   :  Copyright © 2012-2014 Krzysztof Kardzis+-- License     :  ISC License (MIT/BSD-style, see LICENSE file for details)+-- +-- Maintainer  :  Krzysztof Kardzis <kkardzis@gmail.com>+-- Stability   :  experimental+-- Portability :  non-portable+--+-- <<http://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURL000>>+-------------------------------------------------------------------------------++module Network.CURL000 (+  -----------------------------------------------------------------------------+  -- * Run-Time Linking+  -----------------------------------------------------------------------------+    module Network.CURL000.LibLD++  ) where++import Network.CURL000.LibLD+
Network/CURL000/LibHS.hsc view
@@ -542,7 +542,7 @@   #{setopt CURLOPT_ISSUERCERT             , string   }   #{setopt CURLOPT_CAPATH                 , string   }   #{setopt CURLOPT_CRLFILE                , string   }-  #{setopt CURLOPT_SSL_VERIFYHOST         , clong    }+  #{setopt CURLOPT_SSL_VERIFYHOST         , bool2    }   #{setopt CURLOPT_CERTINFO               , bool     }   #{setopt CURLOPT_RANDOM_FILE            , string   }   #{setopt CURLOPT_EGDSOCKET              , string   }@@ -574,10 +574,12 @@     ---------------------------------------------------------------------------     enum  ccurl copt x = C.curl_easy_setopt'Long ccurl copt (toCLong      x)     bool  ccurl copt x = C.curl_easy_setopt'Long ccurl copt (fromBool     x)+    bool2 ccurl copt x = C.curl_easy_setopt'Long ccurl copt (fromBool2    x)     time  ccurl copt x = C.curl_easy_setopt'Long ccurl copt (fromUTCTime  x)     clong ccurl copt x = C.curl_easy_setopt'Long ccurl copt (fromIntegral x)     int64 ccurl copt x = C.curl_easy_setopt'COff ccurl copt (fromIntegral x)     fromUTCTime = truncate . utcTimeToPOSIXSeconds+    fromBool2 False = 0; fromBool2 True = 2     ---------------------------------------------------------------------------     string ccurl copt x = withCAString x $ \p ->       C.curl_easy_setopt'DPtr ccurl copt (castPtr p)
Network/CURL000/Types.hsc view
@@ -628,7 +628,7 @@   | CURLOPT_ISSUERCERT              FilePath   | CURLOPT_CAPATH                  FilePath   | CURLOPT_CRLFILE                 FilePath-  | CURLOPT_SSL_VERIFYHOST          CLong+  | CURLOPT_SSL_VERIFYHOST          Bool   | CURLOPT_CERTINFO                Bool   | CURLOPT_RANDOM_FILE             FilePath   | CURLOPT_EGDSOCKET               String
Network/CURL720.hs view
@@ -8,25 +8,22 @@ -- Stability   :  experimental -- Portability :  non-portable ----- <<https://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURL720>>+-- <<http://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURL720>> -------------------------------------------------------------------------------  module Network.CURL720-  ( module Network.CURLXXX+  ( module Network.CURL000    -- |-  -- To use functions from this module it is required to explicitly link-  -- with @libcurl\/7.20@ (or newer) at runtime. So first things first:+  -- Using functions from this module requires an explicit linking+  -- with @libcurl\/7.20@ or newer at program runtime:   --   -- > main = withlib CURL720 $ do   -- >   ...   ---  -- Without such statement any use of the 'curl*' functions will fail.-  -- Runtime linker will first try to load @libcurl@ binary image into-  -- memory and after succesful loading, library version will be checked.-  -- Standard dynamic loader search path is used to locate required-  -- so\/dll\/dylib. Just install libcurl.so\/dll\/dylib into one of-  -- the searched places (could be current directory).+  -- Without that, any foreign call to @libcurl@ will fail.+  --+  -- More info may be found in the <docs>.    -------------------------------------------------------------------------------@@ -521,5 +518,5 @@  import Network.CURL000.LibHS import Network.CURL000.Types-import Network.CURLXXX+import Network.CURL000 
Network/CURL730.hs view
@@ -8,25 +8,22 @@ -- Stability   :  experimental -- Portability :  non-portable ----- <<https://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURL730>>+-- <<http://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURL730>> -------------------------------------------------------------------------------  module Network.CURL730-  ( module Network.CURLXXX+  ( module Network.CURL000    -- |-  -- To use functions from this module it is required to explicitly link-  -- with @libcurl\/7.30@ (or newer) at runtime. So first things first:+  -- Using functions from this module requires an explicit linking+  -- with @libcurl\/7.30@ or newer at program runtime:   --   -- > main = withlib CURL730 $ do   -- >   ...   ---  -- Without such statement any use of the 'curl*' functions will fail.-  -- Runtime linker will first try to load @libcurl@ binary image into-  -- memory and after succesful loading, library version will be checked.-  -- Standard dynamic loader search path is used to locate required-  -- so\/dll\/dylib. Just install libcurl.so\/dll\/dylib into one of-  -- the searched places (could be current directory).+  -- Without that, any foreign call to @libcurl@ will fail.+  --+  -- More info may be found in the <docs>.   -------------------------------------------------------------------------------@@ -571,5 +568,5 @@  import Network.CURL000.LibHS import Network.CURL000.Types-import Network.CURLXXX+import Network.CURL000 
− Network/CURLXXX.hs
@@ -1,23 +0,0 @@----------------------------------------------------------------------------------- |--- Module      :  Network.CURLXXX--- Copyright   :  Copyright © 2012-2014 Krzysztof Kardzis--- License     :  ISC License (MIT/BSD-style, see LICENSE file for details)--- --- Maintainer  :  Krzysztof Kardzis <kkardzis@gmail.com>--- Stability   :  experimental--- Portability :  non-portable------ <<https://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs/CURLXXX>>----------------------------------------------------------------------------------module Network.CURLXXX (-  ------------------------------------------------------------------------------  -- * Run-Time Linking-  ------------------------------------------------------------------------------    module Network.CURL000.LibLD--  ) where--import Network.CURL000.LibLD-
README.md view
@@ -1,15 +1,23 @@-# Network.CURL [![Build Status][travis.img]][travis.htm]+# Network.CURL [![Hackage][hackage.img]][hackage.htm] [![Build Status][travis.img]][travis.htm] -Package *curlhs* provides Haskell bindings to *libcurl*, the multiprotocol-file transfer library which powers the popular tool *curl*-(see http://curl.haxx.se/libcurl for more info).+Package [*curlhs*][hackage.htm] provides a mid-level [Haskell][haskell.htm]+interface to *libcurl*, the multiprotocol file transfer library which powers+the popular tool *curl* (please see <http://curl.haxx.se/> for more info+about *curl* and *libcurl*). +# Documentation+More info about *curlhs*, such as tutorials or examples, may be found in the+[docs](docs) section. Please check out the short [tutorial](docs/tutorial.md)+about installation and basic usage of *curlhs* and *libcurl*. -[![Analytics][ga.img]][ga.htm] -[ga.img]: https://ga-beacon.appspot.com/UA-53767359-1/github/curlhs-[ga.htm]: https://github.com/igrigorik/ga-beacon  [travis.img]: https://travis-ci.org/kkardzis/curlhs.svg [travis.htm]: https://travis-ci.org/kkardzis/curlhs +[hackage.img]: https://img.shields.io/hackage/v/curlhs.svg+[hackage.htm]: https://hackage.haskell.org/package/curlhs++[haskell.htm]: http://www.haskell.org/++![GA](https://ga-beacon.appspot.com/UA-53767359-1/curlhs/readme)
curlhs.cabal view
@@ -1,24 +1,29 @@-name:           curlhs-version:        0.1.1-synopsis:       bindings to libcurl, the multiprotocol file transfer library-author:         Krzysztof Kardzis <kkardzis@gmail.com>-maintainer:     Krzysztof Kardzis <kkardzis@gmail.com>-copyright:      Copyright © 2012-2014 Krzysztof Kardzis--- license:     ISC License (MIT/BSD-style, see LICENSE file for details)-license:        OtherLicense-license-file:   LICENSE-category:       Network-stability:      Experimental-build-type:     Simple-cabal-version:  >=1.6-homepage:       https://kkardzis.github.com/curlhs+name:          curlhs+version:       0.1.2+synopsis:      bindings to libcurl, the multiprotocol file transfer library+homepage:      https://kkardzis.github.com/curlhs+category:      Network +author:        Krzysztof Kardzis <kkardzis@gmail.com>+maintainer:    Krzysztof Kardzis <kkardzis@gmail.com>+copyright:     Copyright © 2012-2014 Krzysztof Kardzis+-- license:    ISC License (MIT/BSD-style, see LICENSE file for details)+license:       OtherLicense+license-file:  LICENSE++stability:     Experimental+build-type:    Simple+cabal-version: >=1.8+-- should be >=1.18 actually, because of 'extra-doc-files', but oh well...+ description:-  Package @curlhs@ provides a mid-level interface to @libcurl@, the-  multiprotocol file transfer library which powers the popular tool @curl@-  (please see <http://curl.haxx.se/> for more info). As described on the-  @libcurl@'s project site (<http://curl.haxx.se/libcurl/>):+  Package @curlhs@ provides a mid-level Haskell interface to @libcurl@,+  the multiprotocol file transfer library which powers the popular tool+  @curl@ (please see <http://curl.haxx.se/> for more info about @curl@+  and @libcurl@). As described on the @libcurl@ project site:   .+  >+  .   /libcurl is a free and easy-to-use client-side URL transfer library,       /   /supporting DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, /   /LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP.  /@@ -36,23 +41,30 @@   /supported, fast, thoroughly documented and is already used by many        /   /known, big and successful companies and numerous applications.            /   .-  Package is distributed under ISC License (MIT/BSD-style, see LICENSE file-  for details). It is marked as @OtherLicense@ due to limitations of Cabal.+  >   .-  <<https://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs>>+  More info about @curlhs@, such as tutorials or examples, may be found+  in the <docs> section (if on Hackage try <docs/docs> or <src/docs>).+  .+  Package is distributed under the+  <http://choosealicense.com/licenses/isc/ ISC License>+  (MIT\/BSD-style, see <src/LICENSE LICENSE> file for details).+  .+  <<http://ga-beacon.appspot.com/UA-53767359-1/hackage/curlhs>> ++------------------------------------------------------------------------------- extra-source-files:   Network/CURL000/curl-7.30.0/COPYING-  Network/CURL000/curl-7.30.0/curl.h-  Network/CURL000/curl-7.30.0/curlbuild.h-  Network/CURL000/curl-7.30.0/curlrules.h-  Network/CURL000/curl-7.30.0/curlver.h-  Network/CURL000/curl-7.30.0/easy.h-  Network/CURL000/curl-7.30.0/multi.h-  Network/CURL000/curl-7.30.0/stdcheaders.h-  Network/CURL000/curl-7.30.0/typecheck-gcc.h+  Network/CURL000/curl-7.30.0/*.h++extra-doc-files:+  docs/examples/*.hs+  docs/index.htm+  docs/*.md   README.md +------------------------------------------------------------------------------- library   ghc-options: -Wall -fwarn-tabs   build-tools: hsc2hs@@ -61,9 +73,9 @@     base ==4.*, rtld, bytestring, time    exposed-modules:+    Network.CURL000     Network.CURL720     Network.CURL730-    Network.CURLXXX    other-modules:     Network.CURL000.LibCC@@ -77,6 +89,22 @@   include-dirs:     Network/CURL000 ++-------------------------------------------------------------------------------+test-suite hspec+  type:           exitcode-stdio-1.0+  build-depends:  base, hspec, curlhs+  ghc-options:    -Wall -fwarn-tabs+  main-is:        Spec.hs+  hs-source-dirs: test++  other-modules:+    Network.CURL000Spec+    Network.CURL720Spec+    Network.CURL730Spec+++------------------------------------------------------------------------------- source-repository head   location: https://github.com/kkardzis/curlhs   type:     git
+ docs/README.md view
@@ -0,0 +1,34 @@+# Documentation++This is the documentation section of the [*curlhs*][hackage.htm] package.+There is not much here right now, but this should change over time.++Please check out the short [tutorial](tutorial.md) about installation+and basic usage of *curlhs* and *libcurl*.+++# Examples++The examples below are translations to Haskell of the examples found at+<http://curl.haxx.se/libcurl/c/example.html>.++### simple HTTP++[Simple.hs](examples/Simple.hs)+shows how to get a remote web page in only four libcurl function calls.++### simple HTTPS++[Https.hs](examples/Https.hs)+gets a single HTTPS page.++### get a remote file in memory only+[GetInMemory.hs](examples/GetInMemory.hs)+describes how you can use the callback system to fetch documents+into a ram buffer with no file writing necessary.++++[hackage.htm]: https://hackage.haskell.org/package/curlhs++![GA](https://ga-beacon.appspot.com/UA-53767359-1/curlhs/docs/readme)
+ docs/examples/GetInMemory.hs view
@@ -0,0 +1,47 @@+-------------------------------------------------------------------------------+-- Based on <http://curl.haxx.se/libcurl/c/getinmemory.html>+-- Example source code to show how the callback function can be used to+-- download data into a chunk of memory instead of storing it in a file.+-------------------------------------------------------------------------------++module GetInMemory where++import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.ByteString.Builder    as BB++import Control.Exception+import Data.Monoid+import Data.IORef++import Network.CURL720+++main = withlib CURL720 $ do+  lbs <- curlGET "http://httpbin.org/get"+  BL.putStrLn lbs+++curlGET :: String -> IO BL.ByteString+curlGET url =+  bracket (curl_easy_init) (curl_easy_cleanup) $ \curl -> do+    ref <- newIORef mempty+    curl_easy_setopt curl+      [ CURLOPT_URL url+      -- specify URL to get+ +      , CURLOPT_WRITEFUNCTION $ Just (memwrite ref)+      -- send all data to this function+ +      , CURLOPT_USERAGENT "libcurl-agent/1.0"+      -- some servers don't like requests that are made without a user-agent+      -- field, so we provide one+      ]+    curl_easy_perform curl+    fmap BB.toLazyByteString (readIORef ref)+++memwrite :: IORef BB.Builder -> CURL_write_callback+memwrite ref bs = do+  modifyIORef ref (flip mappend (BB.byteString bs))+  return CURL_WRITEFUNC_OK+
+ docs/examples/Https.hs view
@@ -0,0 +1,35 @@+-------------------------------------------------------------------------------+-- Based on <http://curl.haxx.se/libcurl/c/https.html>+-- Gets a single HTTPS page.+-------------------------------------------------------------------------------++module Https where++import Network.CURL720+++main = withlib CURL720 $ do+  curl <- curl_easy_init+  curl_easy_setopt curl+    [ CURLOPT_URL "https://httpbin.org/get"++    , CURLOPT_SSL_VERIFYPEER True+    -- If you want to connect to a site who isn't using a certificate that is+    -- signed by one of the certs in the CA bundle you have, you can skip the+    -- verification of the server's certificate. This makes the connection+    -- A LOT LESS SECURE.+    --+    -- If you have a CA cert for the server stored someplace else than in the+    -- default bundle, then the CURLOPT_CAPATH option might come handy for+    -- you.++    , CURLOPT_SSL_VERIFYHOST True+    -- If the site you're connecting to uses a different host name that what+    -- they have mentioned in their server certificate's commonName (or+    -- subjectAltName) fields, libcurl will refuse to connect. You can skip+    -- this check, but this will make the connection less secure.++    ]+  curl_easy_perform curl+  curl_easy_cleanup curl+
+ docs/examples/Simple.hs view
@@ -0,0 +1,19 @@+-------------------------------------------------------------------------------+-- Based on <http://curl.haxx.se/libcurl/c/simple.html>+-- Shows how to get a remote web page in only four libcurl function calls.+-------------------------------------------------------------------------------++module Simple where++import Network.CURL720+++main = withlib CURL720 $ do+  curl <- curl_easy_init+  curl_easy_setopt curl+    [ CURLOPT_URL "http://httpbin.org/get"+    , CURLOPT_FOLLOWLOCATION True+    ]+  curl_easy_perform curl+  curl_easy_cleanup curl+
+ docs/index.htm view
@@ -0,0 +1,85 @@+<!DOCTYPE html><!-- Simple Markdown Browser by Krzysztof Kardzis -->+<html ng-app="App" ng-controller="AppCtrl">++<head>+<meta charset="utf-8">+<title ng-bind="mdpage"></title>+<link rel="stylesheet" ng-href="{{github1css}}">+<link rel="stylesheet" ng-href="{{github2css}}">+<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/octicons/2.0.2/octicons.min.css">+<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.25/angular.min.js"></script>+<script>+(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){+(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),+m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)+})(window,document,'script','//www.google-analytics.com/analytics.js','ga');+ga('create', 'UA-53767359-2', 'auto');+</script>+</head>++<body>++<div ng-show="ready" class="container" style="padding-top:20px">+  <div id="readme" class="boxed-group ng-cloak">+    <h3>+      <span class="octicon octicon-book"></span>+      <a ng-href="{{mdfile}}">{{mdfile}}</a>+    </h3>+    <article class="markdown-body" ng-bind-html="mdhtml"></article>+  </div>+</div>++<script>+angular.module('App', []).controller('AppCtrl',+function ($scope, $http, $location, $anchorScroll, $sce, $timeout) {+  $http.get('https://cors-anywhere.herokuapp.com/https://github.com').+    error(function(raw) { $scope.ready = true; }).+    success(function(raw) {+      var reg = /href="([^"]+github2?-[^"]+\.css)"/g;+      var cs1; if (cs1=reg.exec(raw)) {$scope.github1css = cs1[1];};+      var cs2; if (cs2=reg.exec(raw)) {$scope.github2css = cs2[1];};+      var css = getComputedStyle(document.getElementById('readme'));+      var check = function () {+        var ready = css.position === 'relative';+        if (ready) { $scope.ready = true; } else { $timeout(check, 10); };+      }; $timeout(check, 10);+    });+  $scope.cache = {};+  $scope.$on('$locationChangeSuccess', function() {+    var mdfile = $location.path().replace(/^\//, '') || 'README.md';+    var mdlink = $location.absUrl().replace(/\/\#\//, '/');+    var mdpage = 'curlhs: ' + mdfile;+    ga('send', 'pageview', {'location': mdlink, 'title': mdpage});+    var mdshow = function () {+      $scope.mdfile = mdfile; $scope.mdpage = mdpage;+      $scope.mdhtml = $scope.cache[mdfile]+      $timeout($anchorScroll);+    };+    if ($scope.cache[mdfile]) { mdshow(); } else {+      var onfail = function(data, statusnum, headers, config, statustxt) {+        $scope.mdfile = mdfile; $scope.mdpage = mdpage;+        $scope.mdhtml = $sce.trustAsHtml+          ( '<h1>' + statusnum.toString() + ' - ' + statustxt + '</h1>'+          + '<pre>' + config.method + ' ' + config.url + '</pre>'+          + '<pre>' + JSON.stringify(headers(), null, 2) + '</pre>');+      };+      $http.get(mdfile).error(onfail).success(function(raw) {+        var cfg = {'headers':{'content-type':'text/plain'}};+        var url = 'https://api.github.com/markdown/raw';+        var ext; if (ext=/\.([^\.]+)$/.exec(mdfile)) {ext = ext[1];};+        if (ext !== 'md') {raw = '```' + ext + '\n' + raw + '\n```';};+        raw = raw.replace('UA-53767359-1', 'UA-53767359-1/hackage');+        $http.post(url, raw, cfg).error(onfail).success(function(data) {+          $scope.cache[mdfile] = $sce.trustAsHtml(data+            .replace(/(href="#)([^"]+")/g,'$1/'+mdfile+'#$2 id="$2')+            .replace(/(href="(?![\/#]))([^":]+")/g,'$1#/$2')+          ); mdshow();+        });+      });+    };+  });+});+</script>++</body>+</html>
+ docs/tutorial.md view
@@ -0,0 +1,256 @@+# 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 <http://curl.haxx.se/libcurl/>+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: <curlhs> failed to call 'curl_version' (NULL)+```++Obviously 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 it at compile/build+time like usually. It is required to explicitly load *libcurl* at runtime.+So let's try:++```hs+ghci> loadlib CURL720+*** Exception: <curlhs> failed to load libcurl/7.20 ["libcurl.dll"]+```++What now? Let's assume we are on Windows, where *libcurl* is not installed+by default. 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 sources of course, but the recommended+way is to search for the precompiled binaries for Windows.+Good place to start may be at <http://www.confusedbycode.com/curl/>.++Be carefull however. *libcurl* uses many different libraries behind the scenes +to do its work, some of them may be optional, some none. It may be build+with different implementations of SSL for example, or even without SSL+support at all. The same with other features, so pay attention to how+a package was build and that all dependencies are included.++Good choice, though not the latest now, are these packages from+<http://curl.haxx.se/download.html>:++* <http://curl.haxx.se/gknw.net/7.34.0/dist-w32/curl-7.34.0-devel-mingw32.zip>+* <http://curl.haxx.se/gknw.net/7.34.0/dist-w64/curl-7.34.0-devel-mingw64.7z>++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 to put those dll's? 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 dll's 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` into the directory where those dll's+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`.+In case *libcurl* is not installed, the easiest way to get 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++Like on Linux systems: first check if *libcurl* is not installed already,+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: <curlhs> 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)
+ test/Network/CURL000Spec.hs view
@@ -0,0 +1,17 @@+module Network.CURL000Spec where++--import Network.CURL000++import Test.Hspec+++main :: IO ()+main = hspec spec++spec :: Spec+spec = do++  describe "RTLD LIBCURL" $ do+    it "load/free libcurl" $ do+      pending+
+ test/Network/CURL720Spec.hs view
@@ -0,0 +1,38 @@+module Network.CURL720Spec where++import Network.CURL720++import Control.Exception (tryJust, ErrorCall (..))++import Text.ParserCombinators.ReadP (ReadP, readP_to_S, string)+import Text.Read.Lex (readDecP)++import Data.List (isPrefixOf)++import Test.Hspec+++testlib :: LIBCURL -> IO (Either String ())+testlib lib =+  let maybeEx s = if (isPrefixOf "<curlhs>" s) then Just s else Nothing+  in  tryJust (\(ErrorCall s) -> maybeEx s) (withlib lib (return ()))+++main :: IO ()+main = hspec spec++spec :: Spec+spec = runIO (testlib CURL720) >>= \x -> case x of+  Left  xs -> it "cannot test this module" (pendingWith xs)+  Right () -> before (loadlib CURL720) $ after (freelib CURL720) $ do++  ----------------------------+  describe "curl_version" $ do+    it "returns libcurl version string: \"libcurl/7.x.x ...\"" $ do+      curl_version >>= (`shouldContain` "libcurl/7.")++    it "returns libcurl version 7.20 or higher compatible" $ do+      let readP = readP_to_S (string "libcurl/7." >> (readDecP :: ReadP Int))+      let check s = case (readP s) of [(v,_)] -> Just (v>=20); _ -> Nothing+      curl_version >>= (`shouldSatisfy` (\s -> maybe False id (check s)))+
+ test/Network/CURL730Spec.hs view
@@ -0,0 +1,38 @@+module Network.CURL730Spec where++import Network.CURL730++import Control.Exception (tryJust, ErrorCall (..))++import Text.ParserCombinators.ReadP (ReadP, readP_to_S, string)+import Text.Read.Lex (readDecP)++import Data.List (isPrefixOf)++import Test.Hspec+++testlib :: LIBCURL -> IO (Either String ())+testlib lib =+  let maybeEx s = if (isPrefixOf "<curlhs>" s) then Just s else Nothing+  in  tryJust (\(ErrorCall s) -> maybeEx s) (withlib lib (return ()))+++main :: IO ()+main = hspec spec++spec :: Spec+spec = runIO (testlib CURL730) >>= \x -> case x of+  Left  xs -> it "cannot test this module" (pendingWith xs)+  Right () -> before (loadlib CURL730) $ after (freelib CURL730) $ do++  ----------------------------+  describe "curl_version" $ do+    it "returns libcurl version string: \"libcurl/7.x.x ...\"" $ do+      curl_version >>= (`shouldContain` "libcurl/7.")++    it "returns libcurl version 7.30 or higher compatible" $ do+      let readP = readP_to_S (string "libcurl/7." >> (readDecP :: ReadP Int))+      let check s = case (readP s) of [(v,_)] -> Just (v>=30); _ -> Nothing+      curl_version >>= (`shouldSatisfy` (\s -> maybe False id (check s)))+
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}