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 +23/−0
- Network/CURL000/LibHS.hsc +3/−1
- Network/CURL000/Types.hsc +1/−1
- Network/CURL720.hs +8/−11
- Network/CURL730.hs +8/−11
- Network/CURLXXX.hs +0/−23
- README.md +15/−7
- curlhs.cabal +58/−30
- docs/README.md +34/−0
- docs/examples/GetInMemory.hs +47/−0
- docs/examples/Https.hs +35/−0
- docs/examples/Simple.hs +19/−0
- docs/index.htm +85/−0
- docs/tutorial.md +256/−0
- test/Network/CURL000Spec.hs +17/−0
- test/Network/CURL720Spec.hs +38/−0
- test/Network/CURL730Spec.hs +38/−0
- test/Spec.hs +1/−0
+ 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/++
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++
+ 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++
+ 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 #-}