[Python-modules-commits] [pycurl] 123/140: Import pycurl_7.19.3.1.orig.tar.gz

Barry Warsaw barry at moszumanska.debian.org
Wed Oct 1 21:45:16 UTC 2014


This is an automated email from the git hooks/post-receive script.

barry pushed a commit to branch master
in repository pycurl.

commit 8e6f1b9f15258f380b8f8d7252c8c1a6dfe32900
Author: Barry Warsaw <barry at python.org>
Date:   Wed Oct 1 16:44:08 2014 -0400

    Import pycurl_7.19.3.1.orig.tar.gz
---
 AUTHORS                                          |  46 ++
 ChangeLog                                        |  16 +
 INSTALL                                          |  94 ----
 INSTALL.rst                                      | 148 +++++++
 MANIFEST.in                                      |   5 +-
 Makefile                                         |  14 +-
 PKG-INFO                                         |   2 +-
 README.rst                                       |  58 +--
 RELEASE-NOTES.rst                                |   7 +
 doc/callbacks.html                               | 147 -------
 doc/callbacks.rst                                | 122 ++++++
 doc/curlmultiobject.html                         | 135 ------
 doc/curlmultiobject.rst                          | 104 +++++
 doc/curlobject.html                              | 132 ------
 doc/curlobject.rst                               |  95 ++++
 doc/curlshareobject.html                         |  53 ---
 doc/curlshareobject.rst                          |  29 ++
 doc/pycurl.html                                  | 138 ------
 doc/pycurl.rst                                   | 114 +++++
 doc/release-process.rst                          |  25 +-
 setup.py                                         | 535 +++++++++++++----------
 src/pycurl.c                                     |  56 +--
 tests/app.py                                     |  25 +-
 tests/fake-curl/curl-config-empty                |  15 +
 tests/fake-curl/curl-config-libs-and-static-libs |  17 +
 tests/fake-curl/curl-config-ssl-feature-only     |  18 +
 tests/fake-curl/curl-config-ssl-in-libs          |  14 +
 tests/fake-curl/curl-config-ssl-in-static-libs   |  17 +
 tests/ftp_test.py                                |   4 +-
 tests/multi_option_constants_test.py             |  24 +
 tests/setup_test.py                              | 103 +++++
 winbuild.py                                      |   4 +-
 32 files changed, 1267 insertions(+), 1049 deletions(-)

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..01d2a8e
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,46 @@
+Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
+Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
+Copyright (C) 2013-2014 by Oleg Pudeyev <oleg at bsdpower.com>
+
+Please see README, COPYING-LGPL and COPYING-MIT for license information.
+
+The following individuals contributed code to PycURL:
+
+Aaron Hill <visine19 at hotmail.com>
+Adam Guthrie <therigu at users.sourceforge.net>
+Adam Jacob Muller <adam at isprime.com>
+Amit Mongia <amit_mongia at hotmail.com>
+Andjelko Horvat <comel at vingd.com>
+Bastian Kleineidam
+Christopher Warner <cwarner at kernelcode.com>
+Conrad Steenberg <conrad at hep.caltech.edu>
+Daniel Pena Arteaga <dpena at ph.tum.de>
+Domenico Andreoli <cavok at libero.it>
+Dominique <curl-and-python at d242.net>
+Eric S. Raymond <esr at thyrsus.com>
+Gisle Vanem <gvanem at yahoo.no>
+Jakob Truelsen <jakob at scalgo.com>
+Jayne <corvine at gmail.com>
+Jim Patterson
+K.S.Sreeram <sreeram at tachyontech.net>
+Kamil Dudka <kdudka at redhat.com>
+Kevin Ko <kevin.s.ko at gmail.com>
+Marcelo Jorge Vieira <metal at alucinados.com>
+Marien Zwart
+Mark Eichin
+Martin Muenstermann <mamuema at sourceforge.net>
+Matt King <matt at gnik.com>
+Nick Pilon <npilon at oreilly.com>
+Oskari Saarenmaa <os at ohmu.fi>
+Paul Pacheco
+Roland Sommer <rol at ndsommer.de>
+Romuald Brunet <romuald at gandi.net>
+Romulo A. Ceccon <romuloceccon at gmail.com>
+Thomas Hunger <teh at camvine.org>
+Tino Lange <Tino.Lange at gmx.de>
+Tom Pierce <tom.pierce0 at gmail.com>
+Victor Lascurain <bittor at eleka.net>
+Wim Lewis
+Yuhui H <eyecat at gmail.com>
+Yuri Ushakov <yuri.ushakov at gmail.com>
+Zdenek Pavlas <zpavlas at redhat.com>
diff --git a/ChangeLog b/ChangeLog
index 3c90a29..ee89790 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+Version 7.19.3.1 [requires libcurl-7.19.0 or better] - 2014-02-05
+-----------------------------------------------------------------
+
+        * Added --avoid-stdio setup.py option to avoid passing FILE
+          pointers from Python to libcurl. Applies to Python 2 only.
+
+        * Added CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE,
+          CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLMOPT_MAX_HOST_CONNECTIONS
+          CURLMOPT_MAX_PIPELINE_LENGTH, CURLMOPT_MAX_TOTAL_CONNECTIONS
+          multi options (patch by Jakob Truelsen).
+
+        * SSL detection logic changed to consult `curl-config --static-libs`
+          even if `curl-config --libs` succeeded. This should achieve
+          pre-7.19.3 behavior with respect to automatic SSL detection
+          (patch by Andjelko Horvat).
+
 Version 7.19.3 [requires libcurl-7.19.0 or better] - 2014-01-09
 ---------------------------------------------------------------
 
diff --git a/INSTALL b/INSTALL
deleted file mode 100644
index 4440e7a..0000000
--- a/INSTALL
+++ /dev/null
@@ -1,94 +0,0 @@
-NOTE: You need Python and libcurl installed on your system to use or
-build pycurl.  Some RPM distributions of curl/libcurl do not include
-everything necessary to build pycurl, in which case you need to
-install the developer specific RPM which is usually called curl-dev.
-
-
-Distutils
----------
-
-Build and install pycurl with the following commands:
-
-    (if necessary, become root)
-    tar -zxvf pycurl-$VER.tar.gz
-    cd pycurl-$VER
-    python setup.py install
-
-$VER should be substituted with the pycurl version number, e.g. 7.10.5.
-
-Note that the installation script assumes that 'curl-config' can be
-located in your path setting.  If curl-config is installed outside
-your path or you want to force installation to use a particular
-version of curl-config, use the '--curl-config' commandline option to
-specify the location of curl-config.  Example:
-
-    python setup.py install --curl-config=/usr/local/bin/curl-config
-
-If libcurl is linked dynamically with pycurl, you may have to alter the
-LD_LIBRARY_PATH environment variable accordingly.  This normally
-applies only if there is more than one version of libcurl installed,
-e.g. one in /usr/lib and one in /usr/local/lib.
-
-
-easy_install / pip
-----------------
-
-    easy_install pycurl
-    pip install pycurl
-
-If you need to specify an alternate curl-config, it can be done via an
-environment variable:
-
-    export PYCURL_CURL_CONFIG=/usr/local/bin/curl-config
-    easy_install pycurl
-
-The same applies to the SSL backend, if you need to specify it (see the SSL
-section below):
-
-    export PYCURL_SSL_LIBRARY=openssl
-    easy_install pycurl
-
-
-SSL
----
-
-PycURL has locks around crypto functions. In order to compile correct locking
-code, it has to know which SSL library is going to be used by libcurl at
-runtime. setup.py will attempt to automatically detect the SSL library that
-libcurl uses, but this does not always work. In the cases when setup.py cannot
-figure out the SSL library, it must be provided via --with-ssl/--with-gnutls/
---with-nss arguments, just like libcurl's configure script uses, or via
-PYCURL_SSL_LIBRARY=openssl|gnutls|nss environment variable.
-
-Please note the difference in spelling that concerns OpenSSL: the command-line
-argument is --with-ssl, to match libcurl, but the environment variable value is
-"openssl".
-
-
-Windows
--------
-
-First, you will need to obtain dependencies. These can be precompiled binaries
-or source packages that you are going to compile yourself.
-
-For a minimum build you will just need libcurl source. Follow its Windows
-build instructions to build either a static or a DLL version of the library,
-then configure PycURL as follows to use it:
-
-    python setup.py --curl-dir=c:\dev\curl-7.33.0\builds\libcurl-vc-x86-release-dll-ipv6-sspi-spnego-winssl --use-libcurl-dll
-
-Note that --curl-dir does not point to libcurl source but rather to headers
-and compiled libraries.
-
-Additional Windows setup.py options:
-
---use-libcurl-dll - build against libcurl DLL, if not given PycURL will be built
-against libcurl statically.
-
---libcurl-lib-name=libcurl_imp.lib - specify a different name for libcurl
-import library. The default is libcurl.lib which is appropriate for static
-linking and is sometimes the correct choice for dynamic linking as well. The
-other possibility for dynamic linking is libcurl_imp.lib.
-
-A good setup.py target to use is bdist_wininst which produces an executable
-installer that you can run to install PycURL.
diff --git a/INSTALL.rst b/INSTALL.rst
new file mode 100644
index 0000000..e40903f
--- /dev/null
+++ b/INSTALL.rst
@@ -0,0 +1,148 @@
+PycURL Installation
+===================
+
+NOTE: You need Python and libcurl installed on your system to use or
+build pycurl.  Some RPM distributions of curl/libcurl do not include
+everything necessary to build pycurl, in which case you need to
+install the developer specific RPM which is usually called curl-dev.
+
+
+Distutils
+---------
+
+Build and install pycurl with the following commands::
+
+    (if necessary, become root)
+    tar -zxvf pycurl-$VER.tar.gz
+    cd pycurl-$VER
+    python setup.py install
+
+$VER should be substituted with the pycurl version number, e.g. 7.10.5.
+
+Note that the installation script assumes that 'curl-config' can be
+located in your path setting.  If curl-config is installed outside
+your path or you want to force installation to use a particular
+version of curl-config, use the '--curl-config' command line option to
+specify the location of curl-config.  Example::
+
+    python setup.py install --curl-config=/usr/local/bin/curl-config
+
+If libcurl is linked dynamically with pycurl, you may have to alter the
+LD_LIBRARY_PATH environment variable accordingly.  This normally
+applies only if there is more than one version of libcurl installed,
+e.g. one in /usr/lib and one in /usr/local/lib.
+
+PycURL requires that the SSL library that it is built against is the same
+one libcurl, and therefore PycURL, uses at runtime. PycURL's ``setup.py``
+uses ``curl-config`` to attempt to figure out which SSL library libcurl
+was compiled against, however this does not always work. If PycURL is unable
+to determine the SSL library in use it will print a warning similar to
+the following::
+
+    src/pycurl.c:137:4: warning: #warning "libcurl was compiled with SSL support, but configure could not determine which " "library was used; thus no SSL crypto locking callbacks will be set, which may " "cause random crashes on SSL requests" [-Wcpp]
+
+It will then fail at runtime as follows::
+
+    ImportError: pycurl: libcurl link-time ssl backend (openssl) is different from compile-time ssl backend (none/other)
+
+To fix this, you need to tell ``setup.py`` what SSL backend is used::
+
+    python setup.py --with-[ssl|gnutls|nss] install
+
+
+easy_install / pip
+------------------
+
+::
+
+    easy_install pycurl
+    pip install pycurl
+
+If you need to specify an alternate curl-config, it can be done via an
+environment variable::
+
+    export PYCURL_CURL_CONFIG=/usr/local/bin/curl-config
+    easy_install pycurl
+
+The same applies to the SSL backend, if you need to specify it (see the SSL
+note above)::
+
+    export PYCURL_SSL_LIBRARY=[openssl|gnutls|nss]
+    easy_install pycurl
+
+Please note the difference in spelling that concerns OpenSSL: the command-line
+argument is --with-ssl, to match libcurl, but the environment variable value is
+"openssl".
+
+
+Windows
+-------
+
+First, you will need to obtain dependencies. These can be precompiled binaries
+or source packages that you are going to compile yourself.
+
+For a minimum build you will just need libcurl source. Follow its Windows
+build instructions to build either a static or a DLL version of the library,
+then configure PycURL as follows to use it::
+
+    python setup.py --curl-dir=c:\dev\curl-7.33.0\builds\libcurl-vc-x86-release-dll-ipv6-sspi-spnego-winssl --use-libcurl-dll
+
+Note that ``--curl-dir`` does not point to libcurl source but rather to headers
+and compiled libraries.
+
+If libcurl and Python are not linked against the same exact C runtime
+(version number, static/dll, single-threaded/multi-threaded) you must use
+``--avoid-stdio`` option (see below).
+
+Additional Windows setup.py options:
+
+- ``--use-libcurl-dll``: build against libcurl DLL, if not given PycURL will
+  be built against libcurl statically.
+- ``--libcurl-lib-name=libcurl_imp.lib``: specify a different name for libcurl
+  import library. The default is ``libcurl.lib`` which is appropriate for
+  static linking and is sometimes the correct choice for dynamic linking as
+  well. The other possibility for dynamic linking is ``libcurl_imp.lib``.
+- ``--avoid-stdio``: on windows, a process and each library it is using
+  may be linked to its own version of the C runtime (msvcrt).
+  FILE pointers from one C runtime may not be passed to another C runtime.
+  This option prevents direct passing of FILE pointers from Python to libcurl,
+  thus permitting Python and libcurl to be linked against different C runtimes.
+  This option may carry a performance penalty when Python file objects are
+  given directly to PycURL in CURLOPT_READDATA, CURLOPT_WRITEDATA or
+  CURLOPT_WRITEHEADER options. This option applies only on Python 2; on
+  Python 3, file objects no longer expose C library FILE pointers and the
+  C runtime issue does not exist. On Python 3, this option is recognized but
+  does nothing. You can also give ``--avoid-stdio`` option in
+  PYCURL_SETUP_OPTIONS environment variable as follows::
+
+    PYCURL_SETUP_OPTIONS=--avoid-stdio pip install pycurl
+
+A good ``setup.py`` target to use is ``bdist_wininst`` which produces an
+executable installer that you can run to install PycURL.
+
+You may find the following mailing list posts helpful:
+
+- http://curl.haxx.se/mail/curlpython-2009-11/0010.html
+- http://curl.haxx.se/mail/curlpython-2013-11/0002.html
+
+
+winbuild.py
+^^^^^^^^^^^
+
+This script is used to build official PycURL Windows packages. You can
+use it to build a full complement of packages with your own options or modify
+it to build a single package you need.
+
+Prerequisites:
+
+- msysgit_.
+- Appropriate `Python versions`_ installed.
+- MS Visual C++ 9/2008 for Python <= 3.2, MS Visual C++ 10/2010 for
+  Python >= 3.3. Express versions of Visual Studio work fine for this.
+
+.. _msysgit: http://msysgit.github.io/
+.. _Python versions: http://python.org/download/
+
+``winbuild.py`` assumes all programs are installed in their default locations,
+if this is not the case edit it as needed. ``winbuild.py`` can be run
+with Python 2.6, 2.7, 3.2 or 3.3.
diff --git a/MANIFEST.in b/MANIFEST.in
index 25f8ffa..24031e1 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,15 +3,15 @@
 # Manifest template for creating the source distribution.
 #
 
+include AUTHORS
 include COPYING-LGPL
 include COPYING-MIT
 include ChangeLog
-include INSTALL
+include INSTALL.rst
 include MANIFEST.in
 include Makefile
 include README.rst
 include RELEASE-NOTES.rst
-include doc/*.html
 include doc/*.rst
 include examples/*.py
 include examples/tests/*.py
@@ -23,6 +23,7 @@ include tests/*.py
 include tests/certs/*.crt
 include tests/certs/*.key
 include tests/ext/*.sh
+include tests/fake-curl/*
 include tests/matrix/*.patch
 include tests/vsftpd.conf
 include winbuild.py
diff --git a/Makefile b/Makefile
index 082af4f..c45a310 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ all build:
 build-7.10.8:
 	$(PYTHON) setup.py build --curl-config=/home/hosts/localhost/packages/curl-7.10.8/bin/curl-config
 
-test: build
+do-test:
 	mkdir -p tests/tmp
 	PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \
 	PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \
@@ -23,6 +23,8 @@ test: build
 	$(NOSETESTS)
 	./tests/ext/test-suite.sh
 
+test: build do-test
+
 # (needs GNU binutils)
 strip: build
 	strip -p --strip-unneeded build/lib*/*.so
@@ -60,11 +62,13 @@ windist: distclean
 	python2.4 setup_win32_ssl.py bdist_wininst
 	rm -rf build
 
-docs:
-	cd doc && for file in *.rst; do rst2html "$$file" ../www/htdocs/doc/`echo "$$file" |sed -e 's/.rst$$/.html/'`; done
-	rst2html RELEASE-NOTES.rst www/htdocs/release-notes.html
+www docs:
+	mkdir -p build
+	rsync -av www build
+	cd doc && for file in *.rst; do rst2html "$$file" ../build/www/htdocs/doc/`echo "$$file" |sed -e 's/.rst$$/.html/'`; done
+	rst2html RELEASE-NOTES.rst build/www/htdocs/release-notes.html
 
 
-.PHONY: all build test strip install install_lib clean distclean maintainer-clean dist sdist windist
+.PHONY: all build test do-test strip install install_lib clean distclean maintainer-clean dist sdist windist
 
 .NOEXPORT:
diff --git a/PKG-INFO b/PKG-INFO
index 86f09b9..c43896d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: pycurl
-Version: 7.19.3
+Version: 7.19.3.1
 Summary: PycURL -- cURL library module for Python
 Home-page: http://pycurl.sourceforge.net/
 Author: Oleg Pudeyev
diff --git a/README.rst b/README.rst
index 2d8277d..1f9dd50 100644
--- a/README.rst
+++ b/README.rst
@@ -46,63 +46,7 @@ Requirements
 Installation
 ------------
 
-You can install the most recent PycURL version using `easy_install`_::
-
-    easy_install pycurl
-
-or `pip`_::
-
-    pip install pycurl
-
-Installing from source is performed via ``setup.py``::
-
-    python setup.py install
-
-You will need libcurl headers and libraries installed to install PycURL
-from source. PycURL uses ``curl-config`` to determine correct flags/libraries
-to use during compilation; you can override the location of ``curl-config``
-if it is not in PATH or you want to use a custom libcurl installation::
-
-    python setup.py --curl-config=/path/to/curl-config install
-
-Sometimes it is more convenient to use an environment variable, if
-you are not directly invoking ``setup.py``::
-
-    PYCURL_CURL_CONFIG=/path/to/curl-config python setup.py install
-
-``curl-config`` is expected to support the following options:
-
-- ``--version``
-- ``--cflags``
-- ``--libs``
-- ``--static-libs`` (if ``--libs`` does not work)
-
-PycURL requires that the SSL library that it is built against is the same
-one libcurl, and therefore PycURL, uses at runtime. PycURL's ``setup.py``
-uses ``curl-config`` to attempt to figure out which SSL library libcurl
-was compiled against, however this does not always work. If PycURL is unable
-to determine the SSL library in use it will print a warning similar to
-the following::
-
-    src/pycurl.c:137:4: warning: #warning "libcurl was compiled with SSL support, but configure could not determine which " "library was used; thus no SSL crypto locking callbacks will be set, which may " "cause random crashes on SSL requests" [-Wcpp]
-
-It will then fail at runtime as follows::
-
-    ImportError: pycurl: libcurl link-time ssl backend (openssl) is different from compile-time ssl backend (none/other)
-
-To fix this, you need to tell ``setup.py`` what SSL backend is used::
-
-    python setup.py --with-[ssl|gnutls|nss] install
-
-Or use an environment variable::
-
-    PYCURL_SSL_LIBRARY=openssl|gnutls|nss python setup.py installl
-
-Note the difference between ``--with-ssl`` (for compatibility with libcurl) and
-``PYCURL_SSL_LIBRARY=openssl``.
-
-.. _easy_install: http://peak.telecommunity.com/DevCenter/EasyInstall
-.. _pip: http://pypi.python.org/pypi/pip
+Please see README.rst for installation instructions.
 
 Support
 -------
diff --git a/RELEASE-NOTES.rst b/RELEASE-NOTES.rst
index c89466c..7fdd74b 100644
--- a/RELEASE-NOTES.rst
+++ b/RELEASE-NOTES.rst
@@ -1,6 +1,13 @@
 Release Notes
 =============
 
+PycURL 7.19.3.1 - 2014-02-05
+----------------------------
+
+This release restores PycURL's ability to automatically detect SSL library
+in use in most circumstances, thanks to Andjelko Horvat.
+
+
 PycURL 7.19.3 - 2014-01-09
 --------------------------
 
diff --git a/doc/callbacks.html b/doc/callbacks.html
deleted file mode 100644
index 83b1445..0000000
--- a/doc/callbacks.html
+++ /dev/null
@@ -1,147 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>PyCurl: Callbacks</title>
-  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
-  <meta name="revisit-after" content="30 days" />
-  <meta name="robots" content="noarchive, index, follow" />
-</head>
-<body>
-
-<h1>Callbacks</h1>
-
-<p>For more fine-grained control, libcurl allows a
-number of callbacks to be associated with each connection. In
-pycurl, callbacks are defined using the <code>setopt()</code> method for
-Curl objects with options WRITEFUNCTION, READFUNCTION, HEADERFUNCTION,
-PROGRESSFUNCTION, IOCTLFUNCTION, or DEBUGFUNCTION. These options
-correspond to the libcurl options with CURLOPT_* prefix removed.  A
-callback in pycurl must be either a regular Python function, a class
-method or an extension type function.</p>
-
-<p>There are some limitations to some of the options which can be used
-concurrently with the pycurl callbacks compared to the libcurl callbacks.
-This is to allow different callback functions to be associated with
-different Curl objects.  More specifically, WRITEDATA cannot
-be used with WRITEFUNCTION, READDATA cannot be used with READFUNCTION,
-WRITEHEADER cannot be used with HEADERFUNCTION, PROGRESSDATA cannot be
-used with PROGRESSFUNCTION, IOCTLDATA cannot be used with IOCTLFUNCTION,
-and DEBUGDATA cannot be used with DEBUGFUNCTION.
-In practice, these limitations can be overcome by having a callback
-function be a class instance method and rather use the class instance
-attributes to store per object data such as files used in the callbacks.
-</p>
-
-The signature of each callback used in pycurl is as follows:<br/>
-<br/>
-<code>WRITEFUNCTION(</code><em>string</em><code>) </code><em>-> number of characters written<br/>
-</em>
-<br/>
-<code>READFUNCTION(</code><em>number of characters to read</em><code>)</code><em>->
-string</em><br/>
-<br/>
-<code>HEADERFUNCTION(</code><em>string</em><code>)</code><em> -> number of characters written<br/>
-</em><br/>
-<code>PROGRESSFUNCTION(</code><em>download total, downloaded, upload total, uploaded</em><code>) </code><em>-> status</em><br/>
-<br/>
-<code>DEBUGFUNCTION(</code><em>debug message type, debug message string</em><code>)</code>
-<em>-> None<br/></em>
-<br/>
-<code>IOCTLFUNCTION(</code><em>ioctl cmd</em><code>)</code>
-<em>-> status<br/></em>
-<br/>
-
-<p>In addition, <code>READFUNCTION</code> may return
-<code>READFUNC_ABORT</code> or <code>READFUNC_PAUSE</code>. See the libcurl
-documentation for an explanation of these values.
-The <code>WRITEFUNCTION</code> and <code>HEADERFUNCTION</code> callbacks
-may return <code>None</code>, which is an alternate way of indicating that
-the callback has consumed all of the string passed to it.</p>
-
-<hr/>
-
-<h2>Example: Callbacks for document header and body</h2>
-
-<p>This example prints the header data to stderr and the body data to
-stdout.  Also note that neither callback returns the number of bytes
-written.  For WRITEFUNCTION and HEADERFUNCTION callbacks, returning
-None implies that all bytes where written.</p>
-
-<pre>
-    ## Callback function invoked when body data is ready
-    def body(buf):
-        # Print body data to stdout
-        import sys
-        sys.stdout.write(buf)
-        # Returning None implies that all bytes were written
-
-    ## Callback function invoked when header data is ready
-    def header(buf):
-        # Print header data to stderr
-        import sys
-        sys.stderr.write(buf)
-        # Returning None implies that all bytes were written
-
-    c = pycurl.Curl()
-    c.setopt(pycurl.URL, "http://www.python.org/")
-    c.setopt(pycurl.WRITEFUNCTION, body)
-    c.setopt(pycurl.HEADERFUNCTION, header)
-    c.perform()
-</pre>
-
-<h2>Example: Download/upload progress callback</h2>
-
-<p>This example shows how to use the progress callback.  When downloading
-a document, the arguments related to uploads are zero, and vice versa.</p>
-
-<pre>
-    ## Callback function invoked when download/upload has progress
-    def progress(download_t, download_d, upload_t, upload_d):
-        print "Total to download", download_t
-        print "Total downloaded", download_d
-        print "Total to upload", upload_t
-        print "Total uploaded", upload_d
-
-    c.setopt(c.URL, "http://slashdot.org/")
-    c.setopt(c.NOPROGRESS, 0)
-    c.setopt(c.PROGRESSFUNCTION, progress)
-    c.perform()
-</pre>
-
-<h2>Example: Debug callbacks</h2>
-
-<p>This example shows how to use the debug callback.  The debug message
-type is an integer indicating the type of debug message.  The
-VERBOSE option must be enabled for this callback to be invoked.</p>
-
-<pre>
-    def test(debug_type, debug_msg):
-        print "debug(%d): %s" % (debug_type, debug_msg)
-
-    c = pycurl.Curl()
-    c.setopt(pycurl.URL, "http://curl.haxx.se/")
-    c.setopt(pycurl.VERBOSE, 1)
-    c.setopt(pycurl.DEBUGFUNCTION, test)
-    c.perform()
-</pre>
-
-<h2>Other examples</h2>
-<p>The pycurl distribution also contains a number of test scripts and
-examples which show how to use the various callbacks in libcurl.
-For instance, the file 'examples/file_upload.py' in the distribution contains
-example code for using READFUNCTION, 'tests/test_cb.py' shows
-WRITEFUNCTION and HEADERFUNCTION, 'tests/test_debug.py' shows DEBUGFUNCTION,
-and 'tests/test_getinfo.py' shows PROGRESSFUNCTION.</p>
-
-
-<hr />
-<p>
-  <a href="http://validator.w3.org/check/referer"><img align="right"
-     src="http://www.w3.org/Icons/valid-xhtml10"
-     alt="Valid XHTML 1.0!" height="31" width="88" border="0" /></a>
-</p>
-
-</body>
-</html>
diff --git a/doc/callbacks.rst b/doc/callbacks.rst
new file mode 100644
index 0000000..bfe1835
--- /dev/null
+++ b/doc/callbacks.rst
@@ -0,0 +1,122 @@
+Callbacks
+=========
+
+For more fine-grained control, libcurl allows a number of callbacks to be
+associated with each connection. In pycurl, callbacks are defined using the
+``setopt()`` method for Curl objects with options WRITEFUNCTION,
+READFUNCTION, HEADERFUNCTION, PROGRESSFUNCTION, IOCTLFUNCTION, or
+DEBUGFUNCTION. These options correspond to the libcurl options with CURLOPT_*
+prefix removed. A callback in pycurl must be either a regular Python
+function, a class method or an extension type function.
+
+There are some limitations to some of the options which can be used
+concurrently with the pycurl callbacks compared to the libcurl callbacks.
+This is to allow different callback functions to be associated with different
+Curl objects. More specifically, WRITEDATA cannot be used with WRITEFUNCTION,
+READDATA cannot be used with READFUNCTION, WRITEHEADER cannot be used with
+HEADERFUNCTION, PROGRESSDATA cannot be used with PROGRESSFUNCTION, IOCTLDATA
+cannot be used with IOCTLFUNCTION, and DEBUGDATA cannot be used with
+DEBUGFUNCTION. In practice, these limitations can be overcome by having a
+callback function be a class instance method and rather use the class
+instance attributes to store per object data such as files used in the
+callbacks.
+
+The signature of each callback used in pycurl is as follows:
+
+**WRITEFUNCTION**\ (*string*) -> *number of characters written*
+
+**READFUNCTION**\ (*number of characters to read*) -> *string*
+
+**HEADERFUNCTION**\ (*string*) -> *number of characters written*
+
+**PROGRESSFUNCTION**\ (*download total, downloaded, upload total,
+uploaded*) -> *status*
+
+**DEBUGFUNCTION**\ (*debug message type, debug message string*) -> *None*
+
+**IOCTLFUNCTION**\ (*ioctl cmd*) -> *status*
+
+In addition, ``READFUNCTION`` may return ``READFUNC_ABORT`` or
+``READFUNC_PAUSE``. See the libcurl documentation for an explanation of these
+values. The ``WRITEFUNCTION`` and ``HEADERFUNCTION`` callbacks may return
+``None``, which is an alternate way of indicating that the callback has
+consumed all of the string passed to it.
+
+Example: Callbacks for document header and body
+-----------------------------------------------
+
+This example prints the header data to stderr and the body data to stdout.
+Also note that neither callback returns the number of bytes written. For
+WRITEFUNCTION and HEADERFUNCTION callbacks, returning None implies that all
+bytes where written.
+
+::
+
+    ## Callback function invoked when body data is ready
+    def body(buf):
+        # Print body data to stdout
+        import sys
+        sys.stdout.write(buf)
+        # Returning None implies that all bytes were written
+
+    ## Callback function invoked when header data is ready
+    def header(buf):
+        # Print header data to stderr
+        import sys
+        sys.stderr.write(buf)
+        # Returning None implies that all bytes were written
+
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://www.python.org/")
+    c.setopt(pycurl.WRITEFUNCTION, body)
+    c.setopt(pycurl.HEADERFUNCTION, header)
+    c.perform()
+
+Example: Download/upload progress callback
+------------------------------------------
+
+This example shows how to use the progress callback. When downloading a
+document, the arguments related to uploads are zero, and vice versa.
+
+::
+
+    ## Callback function invoked when download/upload has
+    progress
+    def progress(download_t, download_d, upload_t, upload_d):
+        print "Total to download", download_t
+        print "Total downloaded", download_d
+        print "Total to upload", upload_t
+        print "Total uploaded", upload_d
+
+    c.setopt(c.URL, "http://slashdot.org/")
+    c.setopt(c.NOPROGRESS, 0)
+    c.setopt(c.PROGRESSFUNCTION, progress)
+    c.perform()
+
+Example: Debug callbacks
+------------------------
+
+This example shows how to use the debug callback. The debug message type is
+an integer indicating the type of debug message. The VERBOSE option must be
+enabled for this callback to be invoked.
+
+::
+
+    def test(debug_type, debug_msg):
+        print "debug(%d): %s" % (debug_type, debug_msg)
+
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://curl.haxx.se/")
+    c.setopt(pycurl.VERBOSE, 1)
+    c.setopt(pycurl.DEBUGFUNCTION, test)
+    c.perform()
+
+Other examples
+--------------
+
+The pycurl distribution also contains a number of test scripts and examples
+which show how to use the various callbacks in libcurl. For instance, the
+file 'examples/file_upload.py' in the distribution contains example code for
+using READFUNCTION, 'tests/test_cb.py' shows WRITEFUNCTION and
+HEADERFUNCTION, 'tests/test_debug.py' shows DEBUGFUNCTION, and
+'tests/test_getinfo.py' shows PROGRESSFUNCTION.
diff --git a/doc/curlmultiobject.html b/doc/curlmultiobject.html
deleted file mode 100644
index f14827c..0000000
--- a/doc/curlmultiobject.html
+++ /dev/null
@@ -1,135 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>PycURL: CurlMulti Objects</title>
-  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
-  <meta name="revisit-after" content="30 days" />
-  <meta name="robots" content="noarchive, index, follow" />
-</head>
-<body>
-
-<h1>CurlMulti Object</h1>
-
-<p>CurlMulti objects have the following methods: </p>
-
-<dl>
-<dt><code>close()</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_cleanup.html"><code>curl_multi_cleanup()</code></a> in libcurl.
-This method is automatically called by pycurl when a CurlMulti object no
-longer has any references to it, but can also be called
-explicitly.</p>
-</dd>
-
-<dt><code>perform()</code> -> <em>tuple of status and the number of active Curl objects</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_perform.html"><code>curl_multi_perform()</code></a> in libcurl.</p>
-</dd>
-
-<dt><code>add_handle(</code><em>Curl object</em><code>) </code>-> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_add_handle.html"><code>curl_multi_add_handle()</code></a> in libcurl.
-This method  adds an existing and valid Curl object to the CurlMulti
-object.</p>
-
-<p>IMPORTANT NOTE: add_handle does not implicitly add a Python reference
-to the Curl object (and thus does not increase the reference count on the Curl
-object).</p>
-</dd>
-
-<dt><code>remove_handle(</code><em>Curl object</em><code>)</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html"><code>curl_multi_remove_handle()</code></a> in libcurl.
-This method removes an existing and valid Curl object from the CurlMulti
-object.</p>
-
-<p>IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference
-from the Curl object (and thus does not decrease the reference count on the Curl
-object).</p>
-</dd>
-
-<dt><code>fdset()</code> ->
-<em>triple of lists with active file descriptors,
-readable,  writeable, exceptions.</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_fdset.html"><code>curl_multi_fdset()</code></a> in libcurl.
-This method extracts  the file descriptor information from a CurlMulti object.
-The returned  lists can be used with the <code>select</code> module to
-poll for events.</p>
-
-<p>Example usage:</p>
-
-<pre>
-import pycurl
-c = pycurl.Curl()
-c.setopt(pycurl.URL, "http://curl.haxx.se")
-m = pycurl.CurlMulti()
-m.add_handle(c)
-while 1:
-    ret, num_handles = m.perform()
-    if ret != pycurl.E_CALL_MULTI_PERFORM: break
-while num_handles:
-    apply(select.select, m.fdset() + (1,))
-    while 1:
-        ret, num_handles = m.perform()
-        if ret != pycurl.E_CALL_MULTI_PERFORM: break
-</pre>
-</dd>
-
-<dt><code>select(</code><em>timeout</em><code>)</code> ->
-<em>number of ready file descriptors or -1 on timeout</em></dt>
-<dd>
-<p>This is a convenience function which simplifies the combined
-use of <code>fdset()</code> and the <code>select</code> module.</p>
-
-<p>Example usage:</p>
-
-<pre>import pycurl
-c = pycurl.Curl()
-c.setopt(pycurl.URL, "http://curl.haxx.se")
-m = pycurl.CurlMulti()
-m.add_handle(c)
-while 1:
-    ret, num_handles = m.perform()
-    if ret != pycurl.E_CALL_MULTI_PERFORM: break
-while num_handles:
-    ret = m.select(1.0)
-    if ret == -1:  continue
-    while 1:
-        ret, num_handles = m.perform()
-        if ret != pycurl.E_CALL_MULTI_PERFORM: break
-</pre>
-</dd>
-
-<dt><code>info_read(</code><em>[max]</em><code>)</code> ->
-<em>numberof queued messages, a list of successful objects, a list of
-failed objects</em></dt>
-<dd>
-<p>Corresponds to the
-<a href="http://curl.haxx.se/libcurl/c/curl_multi_info_read.html"><code>curl_multi_info_read()</code></a> function in libcurl.
-This method extracts at most <em>max</em> messages
-from the multi stack and returns them in two lists. The first
-list contains the handles which completed successfully and the second
-list contains a tuple <em><curl object, curl error number, curl
-error message></em> for each failed curl object. The number
-of queued messages after this method has been called is also
-returned.</p>
-</dd>
-</dl>
-
-<hr />
-<p>
-  <a href="http://validator.w3.org/check/referer"><img align="right"
-     src="http://www.w3.org/Icons/valid-xhtml10"
-     alt="Valid XHTML 1.0!" height="31" width="88" border="0" /></a>
-</p>
-
-</body>
-</html>
diff --git a/doc/curlmultiobject.rst b/doc/curlmultiobject.rst
new file mode 100644
index 0000000..f09a8c3
--- /dev/null
+++ b/doc/curlmultiobject.rst
@@ -0,0 +1,104 @@
+CurlMulti Object
+================
+
+CurlMulti objects have the following methods:
+
+**close**\ () -> *None*
+
+Corresponds to `curl_multi_cleanup`_ in libcurl. This method is
+automatically called by pycurl when a CurlMulti object no longer has any
+references to it, but can also be called explicitly.
+
+**perform**\ () -> *tuple of status and the number of active Curl objects*
+
+Corresponds to `curl_multi_perform`_ in libcurl.
+
+**add_handle**\ (*Curl object*)  -> *None*
+
+Corresponds to `curl_multi_add_handle`_ in libcurl. This method adds an
+existing and valid Curl object to the CurlMulti object.
+
+IMPORTANT NOTE: add_handle does not implicitly add a Python reference to the
+Curl object (and thus does not increase the reference count on the Curl
+object).
+
+**remove_handle**\ (*Curl object*) -> *None*
+
+Corresponds to `curl_multi_remove_handle`_ in libcurl. This method
+removes an existing and valid Curl object from the CurlMulti object.
+
+IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference
+from the Curl object (and thus does not decrease the reference count on the
+Curl object).
+
+**fdset**\ () -> *triple of lists with active file descriptors, readable,
+writeable, exceptions.*
+
+Corresponds to `curl_multi_fdset`_ in libcurl. This method extracts the
+file descriptor information from a CurlMulti object. The returned lists can
+be used with the ``select`` module to poll for events.
+
+Example usage:
+
+::
+
+    import pycurl
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://curl.haxx.se")
+    m = pycurl.CurlMulti()
+    m.add_handle(c)
+    while 1:
+        ret, num_handles = m.perform()
+        if ret != pycurl.E_CALL_MULTI_PERFORM: break
+    while num_handles:
+        apply(select.select, m.fdset() + (1,))
+        while 1:
+            ret, num_handles = m.perform()
+            if ret != pycurl.E_CALL_MULTI_PERFORM: break
+
+**select**\ (*timeout*) -> *number of ready file descriptors or -1 on timeout*
+
+This is a convenience function which simplifies the combined use of
+``fdset()`` and the ``select`` module.
+
+Example usage:
+
+::
+
+    import pycurl
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://curl.haxx.se")
+    m = pycurl.CurlMulti()
+    m.add_handle(c)
+    while 1:
+        ret, num_handles = m.perform()
+        if ret != pycurl.E_CALL_MULTI_PERFORM: break
+    while num_handles:
+        ret = m.select(1.0)
+        if ret == -1:  continue
+        while 1:
+            ret, num_handles = m.perform()
+            if ret != pycurl.E_CALL_MULTI_PERFORM: break
+
+**info_read**\ (*[max]*) -> *number of queued messages, a list of
+successful objects, a list of failed objects*
+
+Corresponds to the `curl_multi_info_read`_ function in libcurl. This
+method extracts at most *max* messages from the multi stack and returns them
+in two lists. The first list contains the handles which completed
+successfully and the second list contains a tuple *(curl object, curl error
+number, curl error message)* for each failed curl object. The number of
+queued messages after this method has been called is also returned.
+
+.. _curl_multi_cleanup:
+    http://curl.haxx.se/libcurl/c/curl_multi_cleanup.html
+.. _curl_multi_perform:
+    http://curl.haxx.se/libcurl/c/curl_multi_perform.html
+.. _curl_multi_add_handle:
+    http://curl.haxx.se/libcurl/c/curl_multi_add_handle.html
+.. _curl_multi_remove_handle:
+    http://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html
+.. _curl_multi_fdset:
+    http://curl.haxx.se/libcurl/c/curl_multi_fdset.html
+.. _curl_multi_info_read:
+    http://curl.haxx.se/libcurl/c/curl_multi_info_read.html
diff --git a/doc/curlobject.html b/doc/curlobject.html
deleted file mode 100644
index 0de0730..0000000
--- a/doc/curlobject.html
+++ /dev/null
@@ -1,132 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>PycURL: Curl Objects</title>
-  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
-  <meta name="revisit-after" content="30 days" />
-  <meta name="robots" content="noarchive, index, follow" />
-</head>
-<body>
-
-<h1>Curl Object</h1>
-
-<p>Curl objects have the following methods:</p>
-
-<dl>
-<dt><code>close()</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_easy_cleanup.html"><code>curl_easy_cleanup</code></a> in libcurl.
-This method is automatically called by pycurl when a Curl object no longer has
-any references to it, but can also be called explicitly.</p>
-</dd>
-
-<dt><code>perform()</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_easy_perform.html"><code>curl_easy_perform</code></a> in libcurl.</p>
-</dd>
-
-<dt><code>reset()</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a
-href="http://curl.haxx.se/libcurl/c/curl_easy_reset.html"><code>curl_easy_reset</code></a> in libcurl.</p>
-</dd>
-
-
-<dt><code>setopt(</code><em>option, value</em><code>)</code> -> <em>None</em></dt>
-<dd>
-
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_easy_setopt.html"><code>curl_easy_setopt</code></a> in libcurl, where
-<em>option</em> is specified with the CURLOPT_* constants in libcurl,
-except that the CURLOPT_ prefix has been removed.
-(See below for exceptions.)
-The type for
-<em>value</em> depends on the option, and can be either a string,
-integer, long integer, file object, list, or function.</p>
-
-<p>Example usage:</p>
-
-<pre>
-import pycurl
-c = pycurl.Curl()
-c.setopt(pycurl.URL, "http://www.python.org/")
-c.setopt(pycurl.HTTPHEADER, ["Accept:"])
-import StringIO
-b = StringIO.StringIO()
-c.setopt(pycurl.WRITEFUNCTION, b.write)
-c.setopt(pycurl.FOLLOWLOCATION, 1)
-c.setopt(pycurl.MAXREDIRS, 5)
-c.perform()
-print b.getvalue()
-...
-</pre>
-</dd>
-
-<dt><code>getinfo(</code><em>option</em><code>) </code>-> <em>Result</em></dt>
-<dd>
-
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html"><code>curl_easy_getinfo</code></a> in libcurl, where
-<em>option</em> is the same as the CURLINFO_* constants in libcurl,
-except that the CURLINFO_ prefix has been removed.
-(See below for exceptions.)
-<em>Result</em> contains an integer, float or string, depending on
-which option is given. The <code>getinfo</code> method should
-not be called unless <code>perform</code> has been called and
-finished.</p>
-
-<p>Example usage:</p>
-
-<pre>
-import pycurl
-c = pycurl.Curl()
-c.setopt(pycurl.URL, "http://sf.net")
-c.setopt(pycurl.FOLLOWLOCATION, 1)
-c.perform()
-print c.getinfo(pycurl.HTTP_CODE), c.getinfo(pycurl.EFFECTIVE_URL)
-...
---> 200 "http://sourceforge.net/"
-</pre>
-</dd>
-
-<dt><code>pause(</code><em>bitmask</em><code>) </code>-> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_easy_pause.html"><code>curl_easy_pause</code></a>
-in libcurl. The argument should be derived from
-the <code>PAUSE_RECV</code>, <code>PAUSE_SEND</code>, <code>PAUSE_ALL</code>
-and <code>PAUSE_CONT</code> constants.</p>
-
-<dt><code>errstr()</code> -> <em>String</em></dt>
-<dd>
-<p>Returns the internal libcurl error buffer of this handle as a string.</p>
-</dd>
-</dl>
-
-<p>In order to distinguish between similarly-named CURLOPT and
-CURLINFO constants, some have <code>OPT_</code>
-and <code>INFO_</code> prefixes. These are
-<code>INFO_FILETIME</code>, <code>OPT_FILETIME</code>,
-<code>INFO_COOKIELIST</code> (but <code>setopt</code> uses <code>COOKIELIST</code>!),
-<code>INFO_CERTINFO</code>, and <code>OPT_CERTINFO</code>.</p>
-
-<p>The value returned by <code>getinfo(INFO_CERTINFO)</code> is a list
-with one element per certificate in the chain, starting with the leaf;
-each element is a sequence
-of <code>(</code><em>key</em><code>, </code><em>value</em><code>)</code>
-tuples.</p>
-
-<hr />
-<p>
-  <a href="http://validator.w3.org/check/referer"><img align="right"
-     src="http://www.w3.org/Icons/valid-xhtml10"
-     alt="Valid XHTML 1.0!" height="31" width="88" border="0" /></a>
-</p>
-
-</body>
-</html>
diff --git a/doc/curlobject.rst b/doc/curlobject.rst
new file mode 100644
index 0000000..3720766
--- /dev/null
+++ b/doc/curlobject.rst
@@ -0,0 +1,95 @@
+Curl Object
+===========
+
+Curl objects have the following methods:
+
+**close**\ () -> *None*
+
+Corresponds to `curl_easy_cleanup`_ in libcurl. This method is
+automatically called by pycurl when a Curl object no longer has any
+references to it, but can also be called explicitly.
+
+**perform**\ () -> *None*
+
+Corresponds to `curl_easy_perform`_ in libcurl.
+
+**reset**\ () -> *None*
+
+Corresponds to `curl_easy_reset`_ in libcurl.
+
+**setopt**\ (*option, value*) -> *None*
+
+Corresponds to `curl_easy_setopt`_ in libcurl, where *option* is
+specified with the ``CURLOPT_*`` constants in libcurl, except that the
+``CURLOPT_``
+prefix has been removed. (See below for exceptions.) The type for *value*
+depends on the option, and can be either a string, integer, long integer,
+file object, list, or function.
+
+Example usage:
+
+::
+
+    import pycurl
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://www.python.org/")
+    c.setopt(pycurl.HTTPHEADER, ["Accept:"])
+    import StringIO
+    b = StringIO.StringIO()
+    c.setopt(pycurl.WRITEFUNCTION, b.write)
+    c.setopt(pycurl.FOLLOWLOCATION, 1)
+    c.setopt(pycurl.MAXREDIRS, 5)
+    c.perform()
+    print b.getvalue()
+    ...
+
+**getinfo**\ (*option*) -> *Result*
+
+Corresponds to `curl_easy_getinfo`_ in libcurl, where *option* is the
+same as the ``CURLINFO_*`` constants in libcurl, except that the ``CURLINFO_``
+prefix
+has been removed. (See below for exceptions.) *Result* contains an integer,
+float or string, depending on which option is given. The ``getinfo`` method
+should not be called unless ``perform`` has been called and finished.
+
+Example usage:
+
+::
+
+    import pycurl
+    c = pycurl.Curl()
+    c.setopt(pycurl.URL, "http://sf.net")
+    c.setopt(pycurl.FOLLOWLOCATION, 1)
+    c.perform()
+    print c.getinfo(pycurl.HTTP_CODE), c.getinfo(pycurl.EFFECTIVE_URL)
+    ...
+    --> 200 "http://sourceforge.net/"
+
+**pause**\ (*bitmask*) -> *None*
+
+Corresponds to `curl_easy_pause`_ in libcurl. The argument should be
+derived from the ``PAUSE_RECV``, ``PAUSE_SEND``, ``PAUSE_ALL`` and
+``PAUSE_CONT`` constants.
+
+**errstr**\ () -> *String*
+
+Returns the internal libcurl error buffer of this handle as a string.
+
+In order to distinguish between similarly-named CURLOPT and CURLINFO
+constants, some have ``OPT_`` and ``INFO_`` prefixes. These are
+``INFO_FILETIME``, ``OPT_FILETIME``, ``INFO_COOKIELIST`` (but ``setopt`` uses
+``COOKIELIST``!), ``INFO_CERTINFO``, and ``OPT_CERTINFO``.
+
+The value returned by ``getinfo(INFO_CERTINFO)`` is a list with one element
+per certificate in the chain, starting with the leaf; each element is a
+sequence of ``(``*key*``, ``*value*``)`` tuples.
+
+.. _curl_easy_cleanup:
+    http://curl.haxx.se/libcurl/c/curl_easy_cleanup.html
+.. _curl_easy_perform:
+    http://curl.haxx.se/libcurl/c/curl_easy_perform.html
+.. _curl_easy_reset: http://curl.haxx.se/libcurl/c/curl_easy_reset.html
+.. _curl_easy_setopt: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
+.. _curl_easy_getinfo:
+    http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html
+.. _curl_easy_pause: http://curl.haxx.se/libcurl/c/curl_easy_pause.html
diff --git a/doc/curlshareobject.html b/doc/curlshareobject.html
deleted file mode 100644
index a624f48..0000000
--- a/doc/curlshareobject.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>PycURL: CurlShare Objects</title>
-  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
-  <meta name="revisit-after" content="30 days" />
-  <meta name="robots" content="noarchive, index, follow" />
-</head>
-<body>
-
-<h1>CurlShare Object</h1>
-
-<p>CurlShare objects have the following methods:</p>
-
-<dl>
-<dt><code>setopt(</code><em>option, value</em><code>)</code> -> <em>None</em></dt>
-<dd>
-
-<p>Corresponds to
-<a
-href="http://curl.haxx.se/libcurl/c/curl_share_setopt.html"><code>curl_share_setopt</code></a> in libcurl, where
-<em>option</em> is specified with the CURLSHOPT_* constants in libcurl,
-except that the CURLSHOPT_ prefix has been changed to SH_.  Currently,
-<em>value</em> must be either LOCK_DATA_COOKIE or LOCK_DATA_DNS.</p>
-
-<p>Example usage:</p>
-
-<pre>
-import pycurl
-curl = pycurl.Curl()
-s = pycurl.CurlShare()
-s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
-s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)
-curl.setopt(pycurl.URL, 'http://curl.haxx.se')
-curl.setopt(pycurl.SHARE, s)
-curl.perform()
-curl.close()
-</pre>
-</dd>
-
-</dl>
-
-<hr />
-<p>
-  <a href="http://validator.w3.org/check/referer"><img align="right"
-     src="http://www.w3.org/Icons/valid-xhtml10"
-     alt="Valid XHTML 1.0!" height="31" width="88" border="0" /></a>
-</p>
-
-</body>
-</html>
diff --git a/doc/curlshareobject.rst b/doc/curlshareobject.rst
new file mode 100644
index 0000000..cf1d17b
--- /dev/null
+++ b/doc/curlshareobject.rst
@@ -0,0 +1,29 @@
+CurlShare Object
+================
+
+CurlShare objects have the following methods:
+
+**setopt**\ (*option, value*) -> *None*
+
+Corresponds to `curl_share_setopt`_ in libcurl, where *option* is
+specified with the ``CURLSHOPT_*`` constants in libcurl, except that the
+``CURLSHOPT_`` prefix has been changed to ``SH_``. Currently, *value* must be
+either ``LOCK_DATA_COOKIE`` or ``LOCK_DATA_DNS``.
+
+Example usage:
+
+::
+
+    import pycurl
+    curl = pycurl.Curl()
+    s = pycurl.CurlShare()
+    s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
+    s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)
+    curl.setopt(pycurl.URL, 'http://curl.haxx.se')
+    curl.setopt(pycurl.SHARE, s)
+    curl.perform()
+    curl.close()
+
+
+.. _curl_share_setopt:
+    http://curl.haxx.se/libcurl/c/curl_share_setopt.html
diff --git a/doc/pycurl.html b/doc/pycurl.html
deleted file mode 100644
index bde7753..0000000
--- a/doc/pycurl.html
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <title>PycURL Documentation</title>
-  <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
-  <meta name="revisit-after" content="30 days" />
-  <meta name="robots" content="noarchive, index, follow" />
-</head>
-<body>
-
-<h1><tt>PycURL</tt> — A Python Interface To The cURL library</h1>
-
-<p>The pycurl package is a Python interface to libcurl (<a
-href="http://curl.haxx.se/libcurl/">http://curl.haxx.se/libcurl/</a>). pycurl
-has been successfully built and tested with Python versions from
-2.4 to 2.7.</p>
-
-<p>libcurl is a client-side URL transfer library supporting FTP, FTPS,
-HTTP, HTTPS, GOPHER, TELNET, DICT, FILE and LDAP.  libcurl
-also supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploads, proxies,
-cookies, basic authentication, file transfer resume of FTP sessions, HTTP
-proxy tunneling and more.</p>
-
-<p>All the functionality provided by libcurl can used through the
-pycurl interface. The following subsections describe how to use the
-pycurl interface, and assume familiarity with how libcurl works.  For
-information on how libcurl works, please consult the curl library web pages
-(<a href="http://curl.haxx.se/libcurl/c/">http://curl.haxx.se/libcurl/c/</a>).</p>
-
-<hr/>
-
-<h1>Module Functionality</h1>
-
-<dl>
-<dt><code>pycurl.global_init(</code><em>option</em><code>)</code> -><em>None</em></dt>
-
-<dd><p><em>option</em> is one of the constants
-pycurl.GLOBAL_SSL, pycurl.GLOBAL_WIN32, pycurl.GLOBAL_ALL,
-pycurl.GLOBAL_NOTHING, pycurl.GLOBAL_DEFAULT.  Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_global_init.html"><code>curl_global_init()</code></a> in libcurl.</p>
-</dd>
-
-<dt><code>pycurl.global_cleanup()</code> -> <em>None</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_global_cleanup.html"><code>curl_global_cleanup()</code></a> in libcurl.</p>
-</dd>
-
-<dt><code>pycurl.version</code></dt>
-
-<dd><p>This is a string with version information on libcurl,
-corresponding to
-<a href="http://curl.haxx.se/libcurl/c/curl_version.html"><code>curl_version()</code></a> in libcurl.</p>
-
-<p>Example usage:</p>
-<pre>
->>> import pycurl
->>> pycurl.version
-'libcurl/7.12.3 OpenSSL/0.9.7e zlib/1.2.2.1 libidn/0.5.12'
-</pre>
-</dd>
-
-<dt><code>pycurl.version_info()</code> -> <em>Tuple</em></dt>
-<dd>
-<p>Corresponds to
-<a href="http://curl.haxx.se/libcurl/c/curl_version_info.html"><code>curl_version_info()</code></a> in libcurl.
-Returns a tuple of information which is similar to the
-<code>curl_version_info_data</code> struct returned by
-<code>curl_version_info()</code> in libcurl.</p>
-
-<p>Example usage:</p>
-<pre>
->>> import pycurl
->>> pycurl.version_info()
-(2, '7.12.3', 461827, 'i586-pc-linux-gnu', 1565, 'OpenSSL/0.9.7e', 9465951,
-'1.2.2.1', ('ftp', 'gopher', 'telnet', 'dict', 'ldap', 'http', 'file',
-'https', 'ftps'), None, 0, '0.5.12')
-</pre>
-</dd>
-
-<dt><code>pycurl.Curl()</code> -> <em>Curl object</em></dt>
-<dd>
-<p>This function creates a new
-<a href="curlobject.html">Curl object</a> which corresponds to a
-<code>CURL</code> handle in libcurl. Curl objects automatically
-set CURLOPT_VERBOSE to 0, CURLOPT_NOPROGRESS to 1,
-provide a default CURLOPT_USERAGENT and setup
-CURLOPT_ERRORBUFFER to point to a private error buffer.</p>
-</dd>
-
-<dt><code>pycurl.CurlMulti()</code> -> <em>CurlMulti object</em></dt>
-<dd>
-<p>This function creates a new
-<a href="curlmultiobject.html">CurlMulti object</a> which corresponds to
-a <code>CURLM</code> handle in libcurl.</p>
-</dd>
-
-<dt><code>pycurl.CurlShare()</code> -> <em>CurlShare object</em></dt>
-<dd>
-<p>This function creates a new
-<a href="curlshareobject.html">CurlShare object</a> which corresponds to
-a <code>CURLSH</code> handle in libcurl.  CurlShare objects is what you
-pass as an argument to the SHARE option on Curl objects.</p>
-</dd>
-
-</dl>
-
-<hr/>
-
-<h1>Subsections</h1>
-
-<ul>
-  <li><a href="curlobject.html">Curl objects</a></li>
-  <li><a href="curlmultiobject.html">CurlMulti objects</a></li>
-  <li><a href="curlshareobject.html">CurlShare objects</a></li>
-  <li><a href="callbacks.html">Callbacks</a></li>
-  <li><a href="unicode.html">Unicode handling</a></li>
-  <li><a href="files.html">File handling</a></li>
-</ul>
-
-<h1>Documentation For Developers</h1>
-
-<ul>
-  <li><a href="internals.html">Notes on PycURL internals</a></li>
-  <li><a href="release-process.html">Release process</a></li>
-</ul>
-
-<hr />
-<p>
-  <a href="http://validator.w3.org/check/referer"><img align="right"
-     src="http://www.w3.org/Icons/valid-xhtml10"
-     alt="Valid XHTML 1.0!" height="31" width="88" border="0" /></a>
-</p>
-
-</body>
-</html>
diff --git a/doc/pycurl.rst b/doc/pycurl.rst
new file mode 100644
index 0000000..60971df
--- /dev/null
+++ b/doc/pycurl.rst
@@ -0,0 +1,114 @@
+``PycURL`` -- A Python Interface To The cURL library
+====================================================
+
+The pycurl package is a Python interface to `libcurl`_.
+pycurl has been successfully built and
+tested with Python versions from 2.4 to 2.7 and 3.1 to 3.3.
+
+libcurl is a client-side URL transfer library supporting FTP, FTPS, HTTP,
+HTTPS, GOPHER, TELNET, DICT, FILE and LDAP. libcurl also supports HTTPS
+certificates, HTTP POST, HTTP PUT, FTP uploads, proxies, cookies, basic
+authentication, file transfer resume of FTP sessions, HTTP proxy tunneling
+and more.
+
+All the functionality provided by libcurl can used through the pycurl
+interface. The following subsections describe how to use the pycurl
+interface, and assume familiarity with how libcurl works. For information on
+how libcurl works, please consult the `curl library C API`_.
+
+Module Functionality
+--------------------
+
+**pycurl.global_init**\ (*option*) -> *None*
+
+*option* is one of the constants pycurl.GLOBAL_SSL, pycurl.GLOBAL_WIN32,
+pycurl.GLOBAL_ALL, pycurl.GLOBAL_NOTHING, pycurl.GLOBAL_DEFAULT. Corresponds
+to `curl_global_init`_ in libcurl.
+
+**pycurl.global_cleanup**\ () -> *None*
+
+Corresponds to `curl_global_cleanup`_ in libcurl.
+
+**pycurl.version**
+
+This is a string with version information on libcurl, corresponding to
+`curl_version`_ in libcurl.
+
+Example usage:
+
+::
+
+    >>> import pycurl
+    >>> pycurl.version
+    'PycURL/7.19.3 libcurl/7.33.0 OpenSSL/0.9.8x zlib/1.2.7'
+
+**pycurl.version_info**\ () -> *Tuple*
+
+Corresponds to `curl_version_info`_ in libcurl. Returns a tuple of
+information which is similar to the ``curl_version_info_data`` struct
+returned by ``curl_version_info()`` in libcurl.
+
+Example usage:
+
+::
+
+    >>> import pycurl
+    >>> pycurl.version_info()
+    (3, '7.33.0', 467200, 'amd64-portbld-freebsd9.1', 33436, 'OpenSSL/0.9.8x',
+    0, '1.2.7', ('dict', 'file', 'ftp', 'ftps', 'gopher', 'http', 'https',
+    'imap', 'imaps', 'pop3', 'pop3s', 'rtsp', 'smtp', 'smtps', 'telnet',
+    'tftp'), None, 0, None)
+
+**pycurl.Curl**\ () -> *Curl object*
+
+This function creates a new `Curl object`_ which corresponds to a ``CURL``
+handle in libcurl. Curl objects automatically set CURLOPT_VERBOSE to 0,
+CURLOPT_NOPROGRESS to 1, provide a default CURLOPT_USERAGENT and setup
+CURLOPT_ERRORBUFFER to point to a private error buffer.
+
+**pycurl.CurlMulti**\ () -> *CurlMulti object*
+
+This function creates a new `CurlMulti object`_ which corresponds to a
+``CURLM`` handle in libcurl.
+
+**pycurl.CurlShare**\ () -> *CurlShare object*
+
+This function creates a new `CurlShare object`_ which corresponds to a
+``CURLSH`` handle in libcurl. CurlShare objects is what you pass as an
+argument to the SHARE option on Curl objects.
+
+
+Subsections
+-----------
+
+-   `Curl objects`_
+-   `CurlMulti objects`_
+-   `CurlShare objects`_
+-   `Callbacks`_
+-   `Unicode handling`_
+-   `File handling`_
+
+
+Documentation For Developers
+============================
+
+-   `Notes on PycURL internals`_
+-   `Release process`_
+
+.. _libcurl: http://curl.haxx.se/libcurl/
+.. _curl library C API: http://curl.haxx.se/libcurl/c/
+.. _curl_global_init: http://curl.haxx.se/libcurl/c/curl_global_init.html
+.. _curl_global_cleanup: http://curl.haxx.se/libcurl/c/curl_global_cleanup.html
+.. _curl_version: http://curl.haxx.se/libcurl/c/curl_version.html
+.. _curl_version_info: http://curl.haxx.se/libcurl/c/curl_version_info.html
+.. _Curl object: curlobject.html
+.. _Curl objects: curlobject.html
+.. _CurlMulti object: curlmultiobject.html
+.. _CurlMulti objects: curlmultiobject.html
+.. _CurlShare object: curlshareobject.html
+.. _CurlShare objects: curlshareobject.html
+.. _Callbacks: callbacks.html
+.. _Unicode handling: unicode.html
+.. _File handling: files.html
+.. _Notes on PycURL internals: internals.html
+.. _Release process: release-process.html
diff --git a/doc/release-process.rst b/doc/release-process.rst
index 813cd51..e967f41 100644
--- a/doc/release-process.rst
+++ b/doc/release-process.rst
@@ -2,28 +2,29 @@ Release Process
 ===============
 
 1. Ensure changelog is up to date with commits in master.
-2. Run `python setup.py manifest`, check that none of the listed files
+2. Run ``python setup.py manifest``, check that none of the listed files
    should be in MANIFEST.in.
-3. Make sure travis is green for master.
-4. Update version numbers in:
-   - Changelog
+3. Check ``get_data_files()`` in ``setup.py`` to see if any new files should
+   be included in binary distributions.
+4. Make sure travis is green for master.
+5. Update version numbers in:
+   - Changelog (also record release date)
    - setup.py
    - winbuild.py
-   - www/htdocs/index.php
-5. Copy Changelog to www/htdocs.
-6. Draft release notes.
-7. `make docs`.
-8. `python setup.py sdist`.
+   - www/htdocs/index.php (also update release date)
+6. Draft release notes, add to RELEASE-NOTES.rst.
+7. ``make docs``.
+8. ``python setup.py sdist``.
 9. Manually test install the built package.
 10. Build windows packages using winbuild.py.
 11. Add windows packages to downloads repo on github.
 12. Tag the new version.
-13. Register new version with pypi - `python setup.py register`.
-14. Upload source distribution to pypi - `python setup.py sdist upload`.
+13. Register new version with pypi - ``python setup.py register``.
+14. Upload source distribution to pypi - ``python setup.py sdist upload``.
     This recreates the source distribution.
 15. Add the source distribution to downloads repo on github.
 16. Rsync downloads repo to sourceforge.
-17. Rsync www/htdocs to sourceforge.
+17. Rsync build/www/htdocs to sourceforge.
 18. Push tag to github pycurl repo.
 19. Announce release on mailing list.
 20. Link to announcement from website.
diff --git a/setup.py b/setup.py
index 40603ff..d35f151 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@
 
 PACKAGE = "pycurl"
 PY_PACKAGE = "curl"
-VERSION = "7.19.3"
+VERSION = "7.19.3.1"
 
 import glob, os, re, sys, string, subprocess
 import distutils
@@ -24,15 +24,6 @@ except NameError:
 class ConfigurationError(exception_base):
     pass
 
-include_dirs = []
-define_macros = [("PYCURL_VERSION", '"%s"' % VERSION)]
-library_dirs = []
-libraries = []
-runtime_library_dirs = []
-extra_objects = []
-extra_compile_args = []
-extra_link_args = []
-
 
 def fail(msg):
     sys.stderr.write(msg + "\n")
@@ -60,75 +51,270 @@ def scan_argv(s, default=None):
     return p
 
 
-# append contents of an environment variable to library_dirs[]
-def add_libdirs(envvar, sep, fatal=False):
-    v = os.environ.get(envvar)
-    if not v:
-        return
-    for dir in str.split(v, sep):
-        dir = str.strip(dir)
-        if not dir:
-            continue
-        dir = os.path.normpath(dir)
-        if os.path.isdir(dir):
-            if not dir in library_dirs:
-                library_dirs.append(dir)
-        elif fatal:
-            fail("FATAL: bad directory %s in environment variable %s" % (dir, envvar))
-
-
-def configure_windows():
-    # Windows users have to pass --curl-dir parameter to specify path
-    # to libcurl, because there is no curl-config on windows at all.
-    curl_dir = scan_argv("--curl-dir=")
-    if curl_dir is None:
-        fail("Please specify --curl-dir=/path/to/built/libcurl")
-    if not os.path.exists(curl_dir):
-        fail("Curl directory does not exist: %s" % curl_dir)
-    if not os.path.isdir(curl_dir):
-        fail("Curl directory is not a directory: %s" % curl_dir)
-    print("Using curl directory: %s" % curl_dir)
-    include_dirs.append(os.path.join(curl_dir, "include"))
-
-    # libcurl windows documentation states that for linking against libcurl
-    # dll, the import library name is libcurl_imp.lib.
-    # in practice, the library name sometimes is libcurl.lib.
-    # override with: --libcurl-lib-name=libcurl_imp.lib
-    curl_lib_name = scan_argv('--libcurl-lib-name=', 'libcurl.lib')
-
-    if scan_argv("--use-libcurl-dll") is not None:
-        libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
-        extra_link_args.extend(["ws2_32.lib"])
+class ExtensionConfiguration(object):
+    def __init__(self):
+        self.include_dirs = []
+        self.define_macros = [("PYCURL_VERSION", '"%s"' % VERSION)]
+        self.library_dirs = []
+        self.libraries = []
+        self.runtime_library_dirs = []
+        self.extra_objects = []
+        self.extra_compile_args = []
+        self.extra_link_args = []
+        
+        self.configure()
+
+    @property
+    def define_symbols(self):
+        return [symbol for symbol, expansion in self.define_macros]
+
+    # append contents of an environment variable to library_dirs[]
+    def add_libdirs(self, envvar, sep, fatal=False):
+        v = os.environ.get(envvar)
+        if not v:
+            return
+        for dir in str.split(v, sep):
+            dir = str.strip(dir)
+            if not dir:
+                continue
+            dir = os.path.normpath(dir)
+            if os.path.isdir(dir):
+                if not dir in library_dirs:
+                    self.library_dirs.append(dir)
+            elif fatal:
+                fail("FATAL: bad directory %s in environment variable %s" % (dir, envvar))
+
+
+    def configure_unix(self):
+        OPENSSL_DIR = scan_argv("--openssl-dir=")
+        if OPENSSL_DIR is not None:
+            self.include_dirs.append(os.path.join(OPENSSL_DIR, "include"))
+        CURL_CONFIG = os.environ.get('PYCURL_CURL_CONFIG', "curl-config")
+        CURL_CONFIG = scan_argv("--curl-config=", CURL_CONFIG)
+        try:
+            p = subprocess.Popen((CURL_CONFIG, '--version'),
+                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        except OSError:
+            exc = sys.exc_info()[1]
+            msg = 'Could not run curl-config: %s' % str(exc)
+            raise ConfigurationError(msg)
+        stdout, stderr = p.communicate()
+        if p.wait() != 0:
+            msg = "`%s' not found -- please install the libcurl development files or specify --curl-config=/path/to/curl-config" % CURL_CONFIG
+            if stderr:
+                msg += ":\n" + stderr.decode()
+            raise ConfigurationError(msg)
+        libcurl_version = stdout.decode().strip()
+        print("Using %s (%s)" % (CURL_CONFIG, libcurl_version))
+        p = subprocess.Popen((CURL_CONFIG, '--cflags'),
+            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        stdout, stderr = p.communicate()
+        if p.wait() != 0:
+            msg = "Problem running `%s' --cflags" % CURL_CONFIG
+            if stderr:
+                msg += ":\n" + stderr.decode()
+            raise ConfigurationError(msg)
+        for arg in split_quoted(stdout.decode()):
+            if arg[:2] == "-I":
+                # do not add /usr/include
+                if not re.search(r"^\/+usr\/+include\/*$", arg[2:]):
+                    self.include_dirs.append(arg[2:])
+            else:
+                self.extra_compile_args.append(arg)
+
+        # Obtain linker flags/libraries to link against.
+        # In theory, all we should need is `curl-config --libs`.
+        # Apparently on some platforms --libs fails and --static-libs works,
+        # so try that.
+        # If --libs succeeds do not try --static-libs; see
+        # https://github.com/pycurl/pycurl/issues/52 for more details.
+        # If neither --libs nor --static-libs work, fail.
+        #
+        # --libs/--static-libs are also used for SSL detection.
+        # libcurl may be configured such that --libs only includes -lcurl
+        # without any of libcurl's dependent libraries, but the dependent
+        # libraries would be included in --static-libs (unless libcurl
+        # was built with static libraries disabled).
+        # Therefore we largely ignore (see below) --static-libs output for
+        # libraries and flags if --libs succeeded, but consult both outputs
+        # for hints as to which SSL library libcurl is linked against.
+        # More information: https://github.com/pycurl/pycurl/pull/147
+        #
+        # The final point is we should link agaist the SSL library in use
+        # even if libcurl does not tell us to, because *we* invoke functions
+        # in that SSL library. This means any SSL libraries found in
+        # --static-libs are forwarded to our libraries.
+        optbuf = ''
+        sslhintbuf = ''
+        errtext = ''
+        for option in ["--libs", "--static-libs"]:
+            p = subprocess.Popen((CURL_CONFIG, option),
+                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            stdout, stderr = p.communicate()
+            if p.wait() == 0:
+                if optbuf == '':
+                    # first successful call
+                    optbuf = stdout.decode()
+                    # optbuf only has output from this call
+                    sslhintbuf += optbuf
+                else:
+                    # second successful call
+                    sslhintbuf += stdout.decode()
+            else:
+                if optbuf == '':
+                    # no successful call yet
+                    errtext += stderr.decode()
+                else:
+                    # first call succeeded and second call failed
+                    # ignore stderr and the error exit
+                    pass
+        if optbuf == "":
+            msg = "Neither curl-config --libs nor curl-config --static-libs" +\
+                " succeeded and produced output"
+            if errtext:
+                msg += ":\n" + errtext
+            raise ConfigurationError(msg)
+        
+        ssl_lib_detected = False
+        if 'PYCURL_SSL_LIBRARY' in os.environ:
+            ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
+            if ssl_lib in ['openssl', 'gnutls', 'nss']:
+                ssl_lib_detected = True
+                self.define_macros.append(('HAVE_CURL_%s' % ssl_lib.upper(), 1))
+            else:
+                raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
+        ssl_options = {
+            '--with-ssl': 'HAVE_CURL_OPENSSL',
+            '--with-gnutls': 'HAVE_CURL_GNUTLS',
+            '--with-nss': 'HAVE_CURL_NSS',
+        }
+        for option in ssl_options:
+            if scan_argv(option) is not None:
+                for other_option in ssl_options:
+                    if option != other_option:
+                        if scan_argv(other_option) is not None:
+                            raise ConfigurationError('Cannot give both %s and %s' % (option, other_option))
+                ssl_lib_detected = True
+                self.define_macros.append((ssl_options[option], 1))
+
+        # libraries and options - all libraries and options are forwarded
+        # but if --libs succeeded, --static-libs output is ignored
+        for arg in split_quoted(optbuf):
+            if arg[:2] == "-l":
+                self.libraries.append(arg[2:])
+            elif arg[:2] == "-L":
+                self.library_dirs.append(arg[2:])
+            else:
+                self.extra_link_args.append(arg)
+        # ssl detection - ssl libraries are forwarded
+        for arg in split_quoted(sslhintbuf):
+            if arg[:2] == "-l":
+                if not ssl_lib_detected and arg[2:] == 'ssl':
+                    self.define_macros.append(('HAVE_CURL_OPENSSL', 1))
+                    ssl_lib_detected = True
+                    self.libraries.append('ssl')
+                if not ssl_lib_detected and arg[2:] == 'gnutls':
+                    self.define_macros.append(('HAVE_CURL_GNUTLS', 1))
+                    ssl_lib_detected = True
+                    self.libraries.append('gnutls')
+                if not ssl_lib_detected and arg[2:] == 'ssl3':
+                    self.define_macros.append(('HAVE_CURL_NSS', 1))
+                    ssl_lib_detected = True
+                    self.libraries.append('ssl3')
+        if not ssl_lib_detected:
+            p = subprocess.Popen((CURL_CONFIG, '--features'),
+                stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            stdout, stderr = p.communicate()
+            if p.wait() != 0:
+                msg = "Problem running `%s' --features" % CURL_CONFIG
+                if stderr:
+                    msg += ":\n" + stderr.decode()
+                raise ConfigurationError(msg)
+            for feature in split_quoted(stdout.decode()):
+                if feature == 'SSL':
+                    # this means any ssl library, not just openssl
+                    self.define_macros.append(('HAVE_CURL_SSL', 1))
+        else:
+            # if we are configuring for a particular ssl library,
+            # we can assume that ssl is being used
+            self.define_macros.append(('HAVE_CURL_SSL', 1))
+        if not self.libraries:
+            self.libraries.append("curl")
+        
+        # Add extra compile flag for MacOS X
+        if sys.platform[:-1] == "darwin":
+            self.extra_link_args.append("-flat_namespace")
+        
+        # Recognize --avoid-stdio on Unix so that it can be tested
+        self.check_avoid_stdio()
+
+
+    def configure_windows(self):
+        # Windows users have to pass --curl-dir parameter to specify path
+        # to libcurl, because there is no curl-config on windows at all.
+        curl_dir = scan_argv("--curl-dir=")
+        if curl_dir is None:
+            fail("Please specify --curl-dir=/path/to/built/libcurl")
+        if not os.path.exists(curl_dir):
+            fail("Curl directory does not exist: %s" % curl_dir)
+        if not os.path.isdir(curl_dir):
+            fail("Curl directory is not a directory: %s" % curl_dir)
+        print("Using curl directory: %s" % curl_dir)
+        self.include_dirs.append(os.path.join(curl_dir, "include"))
+
+        # libcurl windows documentation states that for linking against libcurl
+        # dll, the import library name is libcurl_imp.lib.
+        # in practice, the library name sometimes is libcurl.lib.
+        # override with: --libcurl-lib-name=libcurl_imp.lib
+        curl_lib_name = scan_argv('--libcurl-lib-name=', 'libcurl.lib')
+
+        if scan_argv("--use-libcurl-dll") is not None:
+            libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
+            self.extra_link_args.extend(["ws2_32.lib"])
+            if str.find(sys.version, "MSC") >= 0:
+                # build a dll
+                self.extra_compile_args.append("-MD")
+        else:
+            self.extra_compile_args.append("-DCURL_STATICLIB")
+            libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
+            self.extra_link_args.extend(["gdi32.lib", "wldap32.lib", "winmm.lib", "ws2_32.lib",])
+
+        if not os.path.exists(libcurl_lib_path):
+            fail("libcurl.lib does not exist at %s.\nCurl directory must point to compiled libcurl (bin/include/lib subdirectories): %s" %(libcurl_lib_path, curl_dir))
+        self.extra_objects.append(libcurl_lib_path)
+        
+        self.check_avoid_stdio()
+        
+        # make pycurl binary work on windows xp.
+        # we use inet_ntop which was added in vista and implement a fallback.
+        # our implementation will not be compiled with _WIN32_WINNT targeting
+        # vista or above, thus said binary won't work on xp.
+        # http://curl.haxx.se/mail/curlpython-2013-12/0007.html
+        self.extra_compile_args.append("-D_WIN32_WINNT=0x0501")
+
         if str.find(sys.version, "MSC") >= 0:
-            # build a dll
-            extra_compile_args.append("-MD")
-    else:
-        extra_compile_args.append("-DCURL_STATICLIB")
-        libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
-        extra_link_args.extend(["gdi32.lib", "wldap32.lib", "winmm.lib", "ws2_32.lib",])
+            self.extra_compile_args.append("-O2")
+            self.extra_compile_args.append("-GF")        # enable read-only string pooling
+            self.extra_compile_args.append("-WX")        # treat warnings as errors
+            p = subprocess.Popen(['cl.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            out, err = p.communicate()
+            match = re.search(r'Version (\d+)', err.decode().split("\n")[0])
+            if match and int(match.group(1)) < 16:
+                # option removed in vs 2010:
+                # connect.microsoft.com/VisualStudio/feedback/details/475896/link-fatal-error-lnk1117-syntax-error-in-option-opt-nowin98/
+                self.extra_link_args.append("/opt:nowin98")  # use small section alignment
 
-    if not os.path.exists(libcurl_lib_path):
-        fail("libcurl.lib does not exist at %s.\nCurl directory must point to compiled libcurl (bin/include/lib subdirectories): %s" %(libcurl_lib_path, curl_dir))
-    extra_objects.append(libcurl_lib_path)
+    if sys.platform == "win32":
+        configure = configure_windows
+    else:
+        configure = configure_unix
     
-    # make pycurl binary work on windows xp.
-    # we use inet_ntop which was added in vista and implement a fallback.
-    # our implementation will not be compiled with _WIN32_WINNT targeting
-    # vista or above, thus said binary won't work on xp.
-    # http://curl.haxx.se/mail/curlpython-2013-12/0007.html
-    extra_compile_args.append("-D_WIN32_WINNT=0x0501")
-
-    if str.find(sys.version, "MSC") >= 0:
-        extra_compile_args.append("-O2")
-        extra_compile_args.append("-GF")        # enable read-only string pooling
-        extra_compile_args.append("-WX")        # treat warnings as errors
-        p = subprocess.Popen(['cl.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        out, err = p.communicate()
-        match = re.search(r'Version (\d+)', err.decode().split("\n")[0])
-        if match and int(match.group(1)) < 16:
-            # option removed in vs 2010:
-            # connect.microsoft.com/VisualStudio/feedback/details/475896/link-fatal-error-lnk1117-syntax-error-in-option-opt-nowin98/
-            extra_link_args.append("/opt:nowin98")  # use small section alignment
+    
+    def check_avoid_stdio(self):
+        if 'PYCURL_SETUP_OPTIONS' in os.environ and '--avoid-stdio' in os.environ['PYCURL_SETUP_OPTIONS']:
+            self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
+        if scan_argv('--avoid-stdio') is not None:
+            self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
 
 def get_bdist_msi_version_hack():
     # workaround for distutils/msi version requirement per
@@ -164,145 +350,14 @@ def get_bdist_msi_version_hack():
     return bdist_msi_version_hack
 
 
-def configure_unix():
-    # Find out the rest the hard way
-    OPENSSL_DIR = scan_argv("--openssl-dir=")
-    if OPENSSL_DIR is not None:
-        include_dirs.append(os.path.join(OPENSSL_DIR, "include"))
-    CURL_CONFIG = os.environ.get('PYCURL_CURL_CONFIG', "curl-config")
-    CURL_CONFIG = scan_argv("--curl-config=", CURL_CONFIG)
-    try:
-        p = subprocess.Popen((CURL_CONFIG, '--version'),
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    except OSError:
-        exc = sys.exc_info()[1]
-        msg = 'Could not run curl-config: %s' % str(exc)
-        raise ConfigurationError(msg)
-    stdout, stderr = p.communicate()
-    if p.wait() != 0:
-        msg = "`%s' not found -- please install the libcurl development files or specify --curl-config=/path/to/curl-config" % CURL_CONFIG
-        if stderr:
-            msg += ":\n" + stderr.decode()
-        raise ConfigurationError(msg)
-    libcurl_version = stdout.decode().strip()
-    print("Using %s (%s)" % (CURL_CONFIG, libcurl_version))
-    p = subprocess.Popen((CURL_CONFIG, '--cflags'),
-        stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-    stdout, stderr = p.communicate()
-    if p.wait() != 0:
-        msg = "Problem running `%s' --cflags" % CURL_CONFIG
-        if stderr:
-            msg += ":\n" + stderr.decode()
-        raise ConfigurationError(msg)
-    for arg in split_quoted(stdout.decode()):
-        if arg[:2] == "-I":
-            # do not add /usr/include
-            if not re.search(r"^\/+usr\/+include\/*$", arg[2:]):
-                include_dirs.append(arg[2:])
-        else:
-            extra_compile_args.append(arg)
-
-    # Obtain linker flags/libraries to link against.
-    # In theory, all we should need is `curl-config --libs`.
-    # Apparently on some platforms --libs fails and --static-libs works,
-    # so try that.
-    # If --libs succeeds do not try --static libs; see
-    # https://github.com/pycurl/pycurl/issues/52 for more details.
-    # If neither --libs nor --static-libs work, fail.
-    optbuf = ""
-    errtext = ''
-    for option in ["--libs", "--static-libs"]:
-        p = subprocess.Popen((CURL_CONFIG, option),
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        stdout, stderr = p.communicate()
-        if p.wait() == 0:
-            optbuf = stdout.decode()
-            break
-        else:
-            errtext += stderr.decode()
-    if optbuf == "":
-        msg = "Neither curl-config --libs nor curl-config --static-libs" +\
-            " succeeded and produced output"
-        if errtext:
-            msg += ":\n" + errtext
-        raise ConfigurationError(msg)
-    libs = split_quoted(optbuf)
-    
-    ssl_lib_detected = False
-    if 'PYCURL_SSL_LIBRARY' in os.environ:
-        ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
-        if ssl_lib in ['openssl', 'gnutls', 'nss']:
-            ssl_lib_detected = True
-            define_macros.append(('HAVE_CURL_%s' % ssl_lib.upper(), 1))
-        else:
-            raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
-    ssl_options = {
-        '--with-ssl': 'HAVE_CURL_OPENSSL',
-        '--with-gnutls': 'HAVE_CURL_GNUTLS',
-        '--with-nss': 'HAVE_CURL_NSS',
-    }
-    for option in ssl_options:
-        if scan_argv(option) is not None:
-            for other_option in ssl_options:
-                if option != other_option:
-                    if scan_argv(other_option) is not None:
-                        raise ConfigurationError('Cannot give both %s and %s' % (option, other_option))
-            ssl_lib_detected = True
-            define_macros.append((ssl_options[option], 1))
-
-    for arg in libs:
-        if arg[:2] == "-l":
-            libraries.append(arg[2:])
-            if not ssl_lib_detected and arg[2:] == 'ssl':
-                define_macros.append(('HAVE_CURL_OPENSSL', 1))
-                ssl_lib_detected = True
-            if not ssl_lib_detected and arg[2:] == 'gnutls':
-                define_macros.append(('HAVE_CURL_GNUTLS', 1))
-                ssl_lib_detected = True
-            if not ssl_lib_detected and arg[2:] == 'ssl3':
-                define_macros.append(('HAVE_CURL_NSS', 1))
-                ssl_lib_detected = True
-        elif arg[:2] == "-L":
-            library_dirs.append(arg[2:])
-        else:
-            extra_link_args.append(arg)
-    if not ssl_lib_detected:
-        p = subprocess.Popen((CURL_CONFIG, '--features'),
-            stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        stdout, stderr = p.communicate()
-        if p.wait() != 0:
-            msg = "Problem running `%s' --features" % CURL_CONFIG
-            if stderr:
-                msg += ":\n" + stderr.decode()
-            raise ConfigurationError(msg)
-        for feature in split_quoted(stdout.decode()):
-            if feature == 'SSL':
-                # this means any ssl library, not just openssl
-                define_macros.append(('HAVE_CURL_SSL', 1))
-    else:
-        # if we are configuring for a particular ssl library,
-        # we can assume that ssl is being used
-        define_macros.append(('HAVE_CURL_SSL', 1))
-    if not libraries:
-        libraries.append("curl")
-    # Add extra compile flag for MacOS X
-    if sys.platform[:-1] == "darwin":
-        extra_link_args.append("-flat_namespace")
-
-
-def configure():
-    if sys.platform == "win32":
-        configure_windows()
-    else:
-        configure_unix()
-
-
-
 def strip_pycurl_options():
     if sys.platform == 'win32':
-        options = ['--curl-dir=', '--curl-lib-name=', '--use-libcurl-dll']
+        options = [
+            '--curl-dir=', '--curl-lib-name=', '--use-libcurl-dll',
+            '--avoid-stdio',
+        ]
     else:
-        options = ['--openssl-dir', '--curl-config']
+        options = ['--openssl-dir=', '--curl-config=', '--avoid-stdio']
     for option in options:
         scan_argv(option)
 
@@ -310,19 +365,20 @@ def strip_pycurl_options():
 ###############################################################################
 
 def get_extension():
+    ext_config = ExtensionConfiguration()
     ext = Extension(
         name=PACKAGE,
         sources=[
             os.path.join("src", "pycurl.c"),
         ],
-        include_dirs=include_dirs,
-        define_macros=define_macros,
-        library_dirs=library_dirs,
-        libraries=libraries,
-        runtime_library_dirs=runtime_library_dirs,
-        extra_objects=extra_objects,
-        extra_compile_args=extra_compile_args,
-        extra_link_args=extra_link_args,
+        include_dirs=ext_config.include_dirs,
+        define_macros=ext_config.define_macros,
+        library_dirs=ext_config.library_dirs,
+        libraries=ext_config.libraries,
+        runtime_library_dirs=ext_config.runtime_library_dirs,
+        extra_objects=ext_config.extra_objects,
+        extra_compile_args=ext_config.extra_compile_args,
+        extra_link_args=ext_config.extra_link_args,
     )
     ##print(ext.__dict__); sys.exit(1)
     return ext
@@ -340,12 +396,13 @@ def get_data_files():
     else:
         datadir = os.path.join("share", "doc", PACKAGE)
     #
-    files = ["ChangeLog", "COPYING-LGPL", "COPYING-MIT", "INSTALL", "README.rst"]
+    files = ["AUTHORS", "ChangeLog", "COPYING-LGPL", "COPYING-MIT",
+        "INSTALL.rst", "README.rst"]
     if files:
         data_files.append((os.path.join(datadir), files))
-    files = glob.glob(os.path.join("doc", "*.html"))
+    files = glob.glob(os.path.join("doc", "*.rst"))
     if files:
-        data_files.append((os.path.join(datadir, "html"), files))
+        data_files.append((os.path.join(datadir, "rst"), files))
     files = glob.glob(os.path.join("examples", "*.py"))
     if files:
         data_files.append((os.path.join(datadir, "examples"), files))
@@ -360,8 +417,6 @@ def get_data_files():
             assert os.path.isfile(f), (f, install_dir)
     return data_files
 
-##print get_data_files(); sys.exit(1)
-
 
 ###############################################################################
 
@@ -401,6 +456,32 @@ def check_manifest():
         if not included:
             print(path)
 
+AUTHORS_PARAGRAPH = 3
+
+def check_authors():
+    f = open('AUTHORS')
+    try:
+        contents = f.read()
+    finally:
+        f.close()
+    
+    paras = contents.split("\n\n")
+    authors_para = paras[AUTHORS_PARAGRAPH]
+    authors = [author for author in authors_para.strip().split("\n")]
+    
+    log = subprocess.check_output(['git', 'log', '--format=%an (%ae)'])
+    for author in log.strip().split("\n"):
+        author = author.replace('@', ' at ').replace('(', '<').replace(')', '>')
+        if author not in authors:
+            authors.append(author)
+    authors.sort()
+    paras[AUTHORS_PARAGRAPH] = "\n".join(authors)
+    f = open('AUTHORS', 'w')
+    try:
+        f.write("\n\n".join(paras))
+    finally:
+        f.close()
+
 ###############################################################################
 
 setup_args = dict(
@@ -475,9 +556,9 @@ if __name__ == "__main__":
         setup(**setup_args)
     elif len(sys.argv) > 1 and sys.argv[1] == 'manifest':
         check_manifest()
+    elif len(sys.argv) > 1 and sys.argv[1] == 'authors':
+        check_authors()
     else:
-        configure()
-        
         setup_args['data_files'] = get_data_files()
         ext = get_extension()
         setup_args['ext_modules'] = [ext]
diff --git a/src/pycurl.c b/src/pycurl.c
index 0a9f7b8..5f6afaa 100644
--- a/src/pycurl.c
+++ b/src/pycurl.c
@@ -1,36 +1,4 @@
 /* PycURL -- cURL Python module
- *
- * Authors:
- *  Copyright (C) 2001-2008 by Kjetil Jacobsen <kjetilja at gmail.com>
- *  Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer <markus at oberhumer.com>
- *  Copyright (C) 2013-2014 by Oleg Pudeyev <oleg at bsdpower.com>
- *
- *  All rights reserved.
- *
- * Contributions:
- *  Tino Lange <Tino.Lange at gmx.de>
- *  Matt King <matt at gnik.com>
- *  Conrad Steenberg <conrad at hep.caltech.edu>
- *  Amit Mongia <amit_mongia at hotmail.com>
- *  Eric S. Raymond <esr at thyrsus.com>
- *  Martin Muenstermann <mamuema at sourceforge.net>
- *  Domenico Andreoli <cavok at libero.it>
- *  Dominique <curl-and-python at d242.net>
- *  Paul Pacheco
- *  Victor Lascurain <bittor at eleka.net>
- *  K.S.Sreeram <sreeram at tachyontech.net>
- *  Jayne <corvine at gmail.com>
- *  Bastian Kleineidam
- *  Mark Eichin
- *  Aaron Hill <visine19 at hotmail.com>
- *  Daniel Pena Arteaga <dpena at ph.tum.de>
- *  Jim Patterson
- *  Yuhui H <eyecat at gmail.com>
- *  Nick Pilon <npilon at oreilly.com>
- *  Thomas Hunger <teh at camvine.org>
- *  Wim Lewis
- *
- * See file README for license information.
  */
 
 #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
@@ -117,6 +85,10 @@
 #define HAVE_CURL_REDIR_POST_303
 #endif
 
+#if LIBCURL_VERSION_NUM >= 0x071E00 /* check for 7.30.0 or greater */
+#define HAVE_CURL_7_30_0_PIPELINE_OPTS
+#endif
+
 /* Python < 2.5 compat for Py_ssize_t */
 #if PY_VERSION_HEX < 0x02050000
 typedef int Py_ssize_t;
@@ -2272,7 +2244,7 @@ do_curl_setopt(CurlObject *self, PyObject *args)
 #undef IS_LONG_OPTION
 #undef IS_OFF_T_OPTION
 
-#if PY_MAJOR_VERSION < 3
+#if PY_MAJOR_VERSION < 3 && !defined(PYCURL_AVOID_STDIO)
     /* Handle the case of file objects */
     if (PyFile_Check(obj)) {
         FILE *fp;
@@ -3200,10 +3172,15 @@ do_multi_setopt(CurlMultiObject *self, PyObject *args)
     if (PyInt_Check(obj)) {
         long d = PyInt_AsLong(obj);
         switch(option) {
-        case CURLMOPT_PIPELINING:
-            curl_multi_setopt(self->multi_handle, option, d);
-            break;
         case CURLMOPT_MAXCONNECTS:
+        case CURLMOPT_PIPELINING:
+#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
+        case CURLMOPT_MAX_HOST_CONNECTIONS:
+        case CURLMOPT_MAX_TOTAL_CONNECTIONS:
+        case CURLMOPT_MAX_PIPELINE_LENGTH:
+	case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
+	case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
+#endif
             curl_multi_setopt(self->multi_handle, option, d);
             break;
         default:
@@ -4870,6 +4847,13 @@ initpycurl(void)
     insint_c(d, "M_SOCKETFUNCTION", CURLMOPT_SOCKETFUNCTION);
     insint_c(d, "M_PIPELINING", CURLMOPT_PIPELINING);
     insint_c(d, "M_MAXCONNECTS", CURLMOPT_MAXCONNECTS);
+#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
+    insint_c(d, "M_MAX_HOST_CONNECTIONS", CURLMOPT_MAX_HOST_CONNECTIONS);
+    insint_c(d, "M_MAX_TOTAL_CONNECTIONS", CURLMOPT_MAX_TOTAL_CONNECTIONS);
+    insint_c(d, "M_MAX_PIPELINE_LENGTH", CURLMOPT_MAX_PIPELINE_LENGTH);
+    insint_c(d, "M_CONTENT_LENGTH_PENALTY_SIZE", CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE);
+    insint_c(d, "M_CHUNK_LENGTH_PENALTY_SIZE", CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE);
+#endif
 
     /* constants for setopt(IPRESOLVE, x) */
     insint_c(d, "IPRESOLVE_WHATEVER", CURL_IPRESOLVE_WHATEVER);
diff --git a/tests/app.py b/tests/app.py
index 78a2064..20658bc 100644
--- a/tests/app.py
+++ b/tests/app.py
@@ -48,12 +48,25 @@ def convert_file(key, file):
         'data': file.read(),
     }
 
-def convert_file(key, file):
-    return {
-        'name': file.name,
-        'filename': file.filename,
-        'data': file.file.read().decode(),
-    }
+if hasattr(bottle, 'FileUpload'):
+    # bottle 0.12
+    def convert_file(key, file):
+        return {
+            'name': file.name,
+            # file.filename lowercases the file name
+            # https://github.com/defnull/bottle/issues/582
+            # raw_filenames is a string on python 3
+            'filename': file.raw_filename,
+            'data': file.file.read().decode(),
+        }
+else:
+    # bottle 0.11
+    def convert_file(key, file):
+        return {
+            'name': file.name,
+            'filename': file.filename,
+            'data': file.file.read().decode(),
+        }
 
 @app.route('/files', method='post')
 def files():
diff --git a/tests/fake-curl/curl-config-empty b/tests/fake-curl/curl-config-empty
new file mode 100755
index 0000000..cf93615
--- /dev/null
+++ b/tests/fake-curl/curl-config-empty
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# A curl-config that returns empty responses as much as possible
+
+output=
+
+while test -n "$1"; do
+  case "$1" in
+  --libs)
+    # --libs or --static-libs must succeed and produce output
+    echo '-lcurl'
+    ;;
+  esac
+  shift
+done
diff --git a/tests/fake-curl/curl-config-libs-and-static-libs b/tests/fake-curl/curl-config-libs-and-static-libs
new file mode 100755
index 0000000..56135e0
--- /dev/null
+++ b/tests/fake-curl/curl-config-libs-and-static-libs
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# A curl-config that returns different libraries in --libs and --static-libs
+
+output=
+
+while test -n "$1"; do
+  case "$1" in
+  --libs)
+    echo '-lcurl -lflurby'
+    ;;
+  --static-libs)
+    echo '-lkzzert'
+    ;;
+  esac
+  shift
+done
diff --git a/tests/fake-curl/curl-config-ssl-feature-only b/tests/fake-curl/curl-config-ssl-feature-only
new file mode 100755
index 0000000..3999f11
--- /dev/null
+++ b/tests/fake-curl/curl-config-ssl-feature-only
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+# A curl-config that indicates SSL is supported but does not say
+# which SSL library is being used
+
+output=
+
+while test -n "$1"; do
+  case "$1" in
+  --libs)
+    echo '-lcurl'
+    ;;
+  --features)
+    echo 'SSL'
+    ;;
+  esac
+  shift
+done
diff --git a/tests/fake-curl/curl-config-ssl-in-libs b/tests/fake-curl/curl-config-ssl-in-libs
new file mode 100755
index 0000000..905024b
--- /dev/null
+++ b/tests/fake-curl/curl-config-ssl-in-libs
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+# A curl-config that returns -lssl in --libs but not in --static-libs
+
+output=
+
+while test -n "$1"; do
+  case "$1" in
+  --libs)
+    echo '-lcurl -lssl'
+    ;;
+  esac
+  shift
+done
diff --git a/tests/fake-curl/curl-config-ssl-in-static-libs b/tests/fake-curl/curl-config-ssl-in-static-libs
new file mode 100755
index 0000000..b3c96c0
--- /dev/null
+++ b/tests/fake-curl/curl-config-ssl-in-static-libs
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+# A curl-config that returns -lssl in --static-libs but not in --libs
+
+output=
+
+while test -n "$1"; do
+  case "$1" in
+  --libs)
+    echo '-lcurl'
+    ;;
+  --static-libs)
+    echo '-lssl'
+    ;;
+  esac
+  shift
+done
diff --git a/tests/ftp_test.py b/tests/ftp_test.py
index a88fc44..5a4d8e8 100644
--- a/tests/ftp_test.py
+++ b/tests/ftp_test.py
@@ -27,7 +27,7 @@ class FtpTest(unittest.TestCase):
         
         result = sio.getvalue().decode()
         assert 'README.rst' in result
-        assert 'INSTALL' in result
+        assert 'INSTALL.rst' in result
     
     # XXX this test needs to be fixed
     def test_quote(self):
@@ -50,4 +50,4 @@ class FtpTest(unittest.TestCase):
         
         result = sio.getvalue().decode()
         assert 'README.rst' in result
-        assert 'INSTALL' in result
+        assert 'INSTALL.rst' in result
diff --git a/tests/multi_option_constants_test.py b/tests/multi_option_constants_test.py
new file mode 100644
index 0000000..d44976c
--- /dev/null
+++ b/tests/multi_option_constants_test.py
@@ -0,0 +1,24 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:ts=4:et
+
+import pycurl
+import unittest
+
+from . import util
+
+class MultiOptionConstantsTest(unittest.TestCase):
+    @util.min_libcurl(7, 30, 0)
+    def test_multi_pipeline_opts(self):
+        assert hasattr(pycurl, 'M_MAX_HOST_CONNECTIONS')
+        assert hasattr(pycurl, 'M_MAX_PIPELINE_LENGTH')
+        assert hasattr(pycurl, 'M_CONTENT_LENGTH_PENALTY_SIZE')
+        assert hasattr(pycurl, 'M_CHUNK_LENGTH_PENALTY_SIZE')
+        assert hasattr(pycurl, 'M_MAX_TOTAL_CONNECTIONS')
+        m = pycurl.CurlMulti()
+        m.setopt(pycurl.M_MAX_HOST_CONNECTIONS, 2)
+        m.setopt(pycurl.M_MAX_PIPELINE_LENGTH, 2)
+        m.setopt(pycurl.M_CONTENT_LENGTH_PENALTY_SIZE, 2)
+        m.setopt(pycurl.M_CHUNK_LENGTH_PENALTY_SIZE, 2)
+        m.setopt(pycurl.M_MAX_TOTAL_CONNECTIONS, 2)
+        m.close()
diff --git a/tests/setup_test.py b/tests/setup_test.py
new file mode 100644
index 0000000..d5b302e
--- /dev/null
+++ b/tests/setup_test.py
@@ -0,0 +1,103 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:ts=4:et
+
+import setup as pycurl_setup
+import unittest
+import os, os.path
+import nose.plugins.skip
+
+try:
+    import functools
+except ImportError:
+    import functools_backport as functools
+
+def set_env(key, new_value):
+    old_value = os.environ.get(key)
+    if new_value is not None:
+        os.environ[key] = new_value
+    elif old_value is not None:
+        del os.environ[key]
+    else:
+        # new and old values are None which mean the variable is not set
+        pass
+    return old_value
+
+def reset_env(key, old_value):
+    # empty string means environment variable was empty
+    # None means it was not set
+    if old_value is not None:
+        os.environ[key] = old_value
+    elif key in os.environ:
+        del os.environ[key]
+
+def using_curl_config(path, ssl_library=None):
+    path = os.path.join(os.path.dirname(__file__), 'fake-curl', path)
+    def decorator(fn):
+        @functools.wraps(fn)
+        def decorated(*args, **kwargs):
+            old_path = set_env('PYCURL_CURL_CONFIG', path)
+            old_ssl_library = set_env('PYCURL_SSL_LIBRARY', ssl_library)
+            try:
+                return fn(*args, **kwargs)
+            finally:
+                reset_env('PYCURL_CURL_CONFIG', old_path)
+                reset_env('PYCURL_SSL_LIBRARY', old_ssl_library)
+        return decorated
+    return decorator
+
+class SetupTest(unittest.TestCase):
+    def test_sanity_check(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # we should link against libcurl, one would expect
+        assert 'curl' in config.libraries
+    
+    @using_curl_config('curl-config-empty')
+    def test_no_ssl(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # do not expect anything to do with ssl
+        assert 'ssl' not in config.libraries
+    
+    @using_curl_config('curl-config-libs-and-static-libs')
+    def test_does_not_use_static_libs(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # should not link against any libraries from --static-libs if
+        # --libs succeeded
+        assert 'flurby' in config.libraries
+        assert 'kzzert' not in config.libraries
+    
+    @using_curl_config('curl-config-ssl-in-libs')
+    def test_ssl_in_libs(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # should link against openssl
+        assert 'ssl' in config.libraries
+    
+    @using_curl_config('curl-config-ssl-in-static-libs')
+    def test_ssl_in_static_libs(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # should link against openssl
+        assert 'ssl' in config.libraries
+    
+    @using_curl_config('curl-config-empty')
+    def test_no_ssl_define(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # ssl define should be off
+        assert 'HAVE_CURL_SSL' not in config.define_symbols
+    
+    @using_curl_config('curl-config-ssl-in-libs')
+    def test_ssl_in_libs_sets_ssl_define(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # ssl define should be on
+        assert 'HAVE_CURL_SSL' in config.define_symbols
+    
+    @using_curl_config('curl-config-ssl-in-static-libs')
+    def test_ssl_in_static_libs_sets_ssl_define(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # ssl define should be on
+        assert 'HAVE_CURL_SSL' in config.define_symbols
+    
+    @using_curl_config('curl-config-ssl-feature-only')
+    def test_ssl_feature_sets_ssl_define(self):
+        config = pycurl_setup.ExtensionConfiguration()
+        # ssl define should be on
+        assert 'HAVE_CURL_SSL' in config.define_symbols
diff --git a/winbuild.py b/winbuild.py
index 2ba10a4..7c41bf5 100644
--- a/winbuild.py
+++ b/winbuild.py
@@ -17,9 +17,9 @@ use_zlib = False
 # which version of zlib to use, will be downloaded from internet
 zlib_version = '1.2.8'
 # which version of libcurl to use, will be downloaded from the internet
-libcurl_version = '7.34.0'
+libcurl_version = '7.35.0'
 # pycurl version to build, we should know this ourselves
-pycurl_version = '7.19.3'
+pycurl_version = '7.19.3.1'
 
 import os, os.path, sys, subprocess, shutil, contextlib
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/pycurl.git



More information about the Python-modules-commits mailing list