diff -pruN 7.44.1-5/AUTHORS 7.45.1-1/AUTHORS
--- 7.44.1-5/AUTHORS	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/AUTHORS	2022-03-09 23:15:49.000000000 +0000
@@ -1,6 +1,6 @@
 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-2021 by Oleg Pudeyev <oleg at bsdpower.com>
+Copyright (C) 2013-2022 by Oleg Pudeyev <code at olegp.name>
 
 Please see README, COPYING-LGPL and COPYING-MIT for license information.
 
diff -pruN 7.44.1-5/ChangeLog 7.45.1-1/ChangeLog
--- 7.44.1-5/ChangeLog	2021-08-15 19:29:59.000000000 +0000
+++ 7.45.1-1/ChangeLog	2022-03-13 07:12:05.000000000 +0000
@@ -1,3 +1,26 @@
+Version 7.45.1 [requires libcurl-7.19.0 or better] - 2022-03-13
+---------------------------------------------------------------
+
+        * Fixed build against libcurl < 7.64.1 (patch by Scott Talbert).
+
+Version 7.45.0 [requires libcurl-7.64.1 or better] - 2022-03-09
+---------------------------------------------------------------
+
+        * Add CURLOPT_MAXLIFETIME_CONN (patch by fsbs).
+
+        * Easy handle duplication support (patch by fsbs).
+
+        * Support for unsetting a number of multi options (patch by fsbs).
+
+        * pycurl classes can now be subclassed (patch by fsbs).
+
+        * Multi callbacks' thread state management fixed (patch by fsbs).
+
+        * Add CURL_LOCK_DATA_PSL (patch by fsbs).
+
+        * Add support for SecureTransport SSL backend (MacOS)
+          (patch by Scott Talbert).
+
 Version 7.44.1 [requires libcurl-7.19.0 or better] - 2021-08-15
 ---------------------------------------------------------------
 
diff -pruN 7.44.1-5/COPYING-MIT 7.45.1-1/COPYING-MIT
--- 7.44.1-5/COPYING-MIT	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/COPYING-MIT	2022-03-09 23:16:38.000000000 +0000
@@ -2,7 +2,7 @@ COPYRIGHT AND PERMISSION NOTICE
 
 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-2021 by Oleg Pudeyev <oleg at bsdpower.com>
+Copyright (C) 2013-2022 by Oleg Pudeyev <code at olegp.name>
 
 All rights reserved.
 
diff -pruN 7.44.1-5/debian/changelog 7.45.1-1/debian/changelog
--- 7.44.1-5/debian/changelog	2022-04-30 22:08:13.000000000 +0000
+++ 7.45.1-1/debian/changelog	2022-08-03 03:02:27.000000000 +0000
@@ -1,3 +1,10 @@
+pycurl (7.45.1-1) unstable; urgency=medium
+
+  * Update to new upstream release 7.45.1
+  * Update Standards-Version to 4.6.1
+
+ -- Scott Talbert <swt@techie.net>  Tue, 02 Aug 2022 23:02:27 -0400
+
 pycurl (7.44.1-5) unstable; urgency=medium
 
   * Team upload.
diff -pruN 7.44.1-5/debian/control 7.45.1-1/debian/control
--- 7.44.1-5/debian/control	2022-04-30 22:08:13.000000000 +0000
+++ 7.45.1-1/debian/control	2022-08-03 03:01:36.000000000 +0000
@@ -17,7 +17,7 @@ Build-Depends: debhelper-compat (= 13),
                vsftpd <!nocheck>,
 Build-Depends-Indep: dh-sequence-sphinxdoc,
                      python3-sphinx,
-Standards-Version: 4.6.0
+Standards-Version: 4.6.1
 X-Python-Version: all
 Homepage: http://pycurl.sourceforge.net
 Vcs-Git: https://salsa.debian.org/python-team/packages/pycurl.git
diff -pruN 7.44.1-5/debian/rules 7.45.1-1/debian/rules
--- 7.44.1-5/debian/rules	2022-04-30 22:08:13.000000000 +0000
+++ 7.45.1-1/debian/rules	2022-08-03 02:57:20.000000000 +0000
@@ -30,7 +30,7 @@ override_dh_auto_test:
 ifeq ($(filter nocheck,$(DEB_BUILD_OPTIONS)),)
 	set -e ;\
 	for py in $(PY3VERS) ; do \
-		make test PYTHON=python$$py PYTEST="python$$py -m pytest" PYTEST_ADDOPTS="--ignore examples -m 'not online'" PYFLAKES="python$$py -m pyflakes" PYCURL_VSFTPD_PATH=vsftpd; \
+		make test PYTHON=python$$py PYTEST="python$$py -m pytest" PYTEST_ADDOPTS="--ignore examples --ignore .pc -m 'not online'" PYFLAKES="python$$py -m pyflakes" PYCURL_VSFTPD_PATH=vsftpd; \
 	done
 endif
 
diff -pruN 7.44.1-5/doc/conf.py 7.45.1-1/doc/conf.py
--- 7.44.1-5/doc/conf.py	2021-08-15 19:30:42.000000000 +0000
+++ 7.45.1-1/doc/conf.py	2022-03-13 07:12:29.000000000 +0000
@@ -47,16 +47,16 @@ master_doc = 'index'
 
 # General information about the project.
 project = u'PycURL'
-copyright = u'2001-2021 Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev'
+copyright = u'2001-2022 Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
 # The short X.Y version.
-version = '7.44.1'
+version = '7.45.1'
 # The full version, including alpha/beta/rc tags.
-release = '7.44.1'
+release = '7.45.1'
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
diff -pruN 7.44.1-5/doc/docstrings/curl_duphandle.rst 7.45.1-1/doc/docstrings/curl_duphandle.rst
--- 7.44.1-5/doc/docstrings/curl_duphandle.rst	1970-01-01 00:00:00.000000000 +0000
+++ 7.45.1-1/doc/docstrings/curl_duphandle.rst	2022-01-11 19:34:56.000000000 +0000
@@ -0,0 +1,23 @@
+duphandle() -> Curl
+
+Clone a curl handle. This function will return a new curl handle,
+a duplicate, using all the options previously set in the input curl handle.
+Both handles can subsequently be used independently.
+
+The new handle will not inherit any state information, no connections,
+no SSL sessions and no cookies. It also will not inherit any share object
+states or options (it will be made as if SHARE was unset).
+
+Corresponds to `curl_easy_duphandle`_ in libcurl.
+
+Example usage::
+
+    import pycurl
+    curl = pycurl.Curl()
+    curl.setopt(pycurl.URL, "https://python.org")
+    dup = curl.duphandle()
+    curl.perform()
+    dup.perform()
+
+.. _curl_easy_duphandle:
+    https://curl.se/libcurl/c/curl_easy_duphandle.html
diff -pruN 7.44.1-5/doc/docstrings/multi_select.rst 7.45.1-1/doc/docstrings/multi_select.rst
--- 7.44.1-5/doc/docstrings/multi_select.rst	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/doc/docstrings/multi_select.rst	2022-01-11 19:23:49.000000000 +0000
@@ -1,4 +1,4 @@
-select([timeout]) -> number of ready file descriptors or -1 on timeout
+select([timeout]) -> number of ready file descriptors or 0 on timeout
 
 Returns result from doing a select() on the curl multi file descriptor
 with the given timeout.
@@ -18,7 +18,7 @@ Example usage::
         if ret != pycurl.E_CALL_MULTI_PERFORM: break
     while num_handles:
         ret = m.select(1.0)
-        if ret == -1:  continue
+        if ret == 0:  continue
         while 1:
             ret, num_handles = m.perform()
             if ret != pycurl.E_CALL_MULTI_PERFORM: break
diff -pruN 7.44.1-5/INSTALL.rst 7.45.1-1/INSTALL.rst
--- 7.44.1-5/INSTALL.rst	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/INSTALL.rst	2022-01-11 19:23:49.000000000 +0000
@@ -53,7 +53,7 @@ It will then fail at runtime as follows:
 
 To fix this, you need to tell ``setup.py`` what SSL backend is used::
 
-    python setup.py --with-[openssl|gnutls|nss|mbedtls|wolfssl] install
+    python setup.py --with-[openssl|gnutls|nss|mbedtls|wolfssl|sectransp] install
 
 Note: as of PycURL 7.21.5, setup.py accepts ``--with-openssl`` option to
 indicate that libcurl is built against OpenSSL/LibreSSL/BoringSSL.
@@ -86,7 +86,7 @@ environment variable::
 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|mbedtls]
+    export PYCURL_SSL_LIBRARY=[openssl|gnutls|nss|mbedtls|sectransp]
     easy_install pycurl
 
 
diff -pruN 7.44.1-5/MANIFEST.in 7.45.1-1/MANIFEST.in
--- 7.44.1-5/MANIFEST.in	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/MANIFEST.in	2021-12-27 23:13:33.000000000 +0000
@@ -10,6 +10,7 @@ include ChangeLog
 include INSTALL.rst
 include MANIFEST.in
 include Makefile
+include pytest.ini
 include README.rst
 include RELEASE-NOTES.rst
 include doc/*.py
diff -pruN 7.44.1-5/PKG-INFO 7.45.1-1/PKG-INFO
--- 7.44.1-5/PKG-INFO	2021-08-15 19:31:41.012168600 +0000
+++ 7.45.1-1/PKG-INFO	2022-03-13 07:13:38.993937500 +0000
@@ -1,6 +1,6 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: pycurl
-Version: 7.44.1
+Version: 7.45.1
 Summary: PycURL -- A Python Interface To The cURL library
 Home-page: http://pycurl.io/
 Author: Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev
@@ -8,86 +8,6 @@ Author-email: kjetilja@gmail.com, markus
 Maintainer: Oleg Pudeyev
 Maintainer-email: oleg@bsdpower.com
 License: LGPL/MIT
-Description: PycURL -- A Python Interface To The cURL library
-        ================================================
-        
-        PycURL is a Python interface to `libcurl`_, the multiprotocol file
-        transfer library. Similarly to the urllib_ Python module,
-        PycURL can be used to fetch objects identified by a URL from a Python program.
-        Beyond simple fetches however PycURL exposes most of the functionality of
-        libcurl, including:
-        
-        - Speed - libcurl is very fast and PycURL, being a thin wrapper above
-          libcurl, is very fast as well. PycURL `was benchmarked`_ to be several
-          times faster than requests_.
-        - Features including multiple protocol support, SSL, authentication and
-          proxy options. PycURL supports most of libcurl's callbacks.
-        - Multi_ and share_ interfaces.
-        - Sockets used for network operations, permitting integration of PycURL
-          into the application's I/O loop (e.g., using Tornado_).
-        
-        .. _was benchmarked: http://stackoverflow.com/questions/15461995/python-requests-vs-pycurl-performance
-        .. _requests: http://python-requests.org/
-        .. _Multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
-        .. _share: https://curl.haxx.se/libcurl/c/libcurl-share.html
-        .. _Tornado: http://www.tornadoweb.org/
-        
-        
-        Requirements
-        ------------
-        
-        - Python 3.5-3.9.
-        - libcurl 7.19.0 or better.
-        
-        
-        Installation
-        ------------
-        
-        Download the source distribution from `PyPI`_.
-        
-        Please see `the installation documentation`_ for installation instructions.
-        
-        .. _PyPI: https://pypi.python.org/pypi/pycurl
-        .. _the installation documentation: http://pycurl.io/docs/latest/install.html
-        
-        
-        Documentation
-        -------------
-        
-        Documentation for the most recent PycURL release is available on
-        `PycURL website <http://pycurl.io/docs/latest/>`_.
-        
-        
-        Support
-        -------
-        
-        For support questions please use `curl-and-python mailing list`_.
-        `Mailing list archives`_ are available for your perusal as well.
-        
-        Although not an official support venue, `Stack Overflow`_ has been
-        popular with some PycURL users.
-        
-        Bugs can be reported `via GitHub`_. Please use GitHub only for bug
-        reports and direct questions to our mailing list instead.
-        
-        .. _curl-and-python mailing list: http://cool.haxx.se/mailman/listinfo/curl-and-python
-        .. _Stack Overflow: http://stackoverflow.com/questions/tagged/pycurl
-        .. _Mailing list archives: https://curl.haxx.se/mail/list.cgi?list=curl-and-python
-        .. _via GitHub: https://github.com/pycurl/pycurl/issues
-        
-        
-        License
-        -------
-        
-        PycURL is dual licensed under the LGPL and an MIT/X derivative license
-        based on the libcurl license. The complete text of the licenses is available
-        in COPYING-LGPL_ and COPYING-MIT_ files in the source distribution.
-        
-        .. _libcurl: https://curl.haxx.se/libcurl/
-        .. _urllib: http://docs.python.org/library/urllib.html
-        .. _COPYING-LGPL: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-LGPL
-        .. _COPYING-MIT: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-MIT
-        
 Keywords: curl,libcurl,urllib,wget,download,file transfer,http,www
 Platform: All
 Classifier: Development Status :: 5 - Production/Stable
@@ -103,6 +23,92 @@ Classifier: Programming Language :: Pyth
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
 Classifier: Topic :: Internet :: WWW/HTTP
 Requires-Python: >=3.5
+License-File: COPYING-LGPL
+License-File: COPYING-MIT
+License-File: AUTHORS
+
+PycURL -- A Python Interface To The cURL library
+================================================
+
+PycURL is a Python interface to `libcurl`_, the multiprotocol file
+transfer library. Similarly to the urllib_ Python module,
+PycURL can be used to fetch objects identified by a URL from a Python program.
+Beyond simple fetches however PycURL exposes most of the functionality of
+libcurl, including:
+
+- Speed - libcurl is very fast and PycURL, being a thin wrapper above
+  libcurl, is very fast as well. PycURL `was benchmarked`_ to be several
+  times faster than requests_.
+- Features including multiple protocol support, SSL, authentication and
+  proxy options. PycURL supports most of libcurl's callbacks.
+- Multi_ and share_ interfaces.
+- Sockets used for network operations, permitting integration of PycURL
+  into the application's I/O loop (e.g., using Tornado_).
+
+.. _was benchmarked: http://stackoverflow.com/questions/15461995/python-requests-vs-pycurl-performance
+.. _requests: http://python-requests.org/
+.. _Multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
+.. _share: https://curl.haxx.se/libcurl/c/libcurl-share.html
+.. _Tornado: http://www.tornadoweb.org/
+
+
+Requirements
+------------
+
+- Python 3.5-3.10.
+- libcurl 7.19.0 or better.
+
+
+Installation
+------------
+
+Download the source distribution from `PyPI`_.
+
+Please see `the installation documentation`_ for installation instructions.
+
+.. _PyPI: https://pypi.python.org/pypi/pycurl
+.. _the installation documentation: http://pycurl.io/docs/latest/install.html
+
+
+Documentation
+-------------
+
+Documentation for the most recent PycURL release is available on
+`PycURL website <http://pycurl.io/docs/latest/>`_.
+
+
+Support
+-------
+
+For support questions please use `curl-and-python mailing list`_.
+`Mailing list archives`_ are available for your perusal as well.
+
+Although not an official support venue, `Stack Overflow`_ has been
+popular with some PycURL users.
+
+Bugs can be reported `via GitHub`_. Please use GitHub only for bug
+reports and direct questions to our mailing list instead.
+
+.. _curl-and-python mailing list: http://cool.haxx.se/mailman/listinfo/curl-and-python
+.. _Stack Overflow: http://stackoverflow.com/questions/tagged/pycurl
+.. _Mailing list archives: https://curl.haxx.se/mail/list.cgi?list=curl-and-python
+.. _via GitHub: https://github.com/pycurl/pycurl/issues
+
+
+License
+-------
+
+PycURL is dual licensed under the LGPL and an MIT/X derivative license
+based on the libcurl license. The complete text of the licenses is available
+in COPYING-LGPL_ and COPYING-MIT_ files in the source distribution.
+
+.. _libcurl: https://curl.haxx.se/libcurl/
+.. _urllib: http://docs.python.org/library/urllib.html
+.. _COPYING-LGPL: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-LGPL
+.. _COPYING-MIT: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-MIT
+
+
diff -pruN 7.44.1-5/pycurl.egg-info/PKG-INFO 7.45.1-1/pycurl.egg-info/PKG-INFO
--- 7.44.1-5/pycurl.egg-info/PKG-INFO	2021-08-15 19:31:40.000000000 +0000
+++ 7.45.1-1/pycurl.egg-info/PKG-INFO	2022-03-13 07:13:38.000000000 +0000
@@ -1,6 +1,6 @@
-Metadata-Version: 1.2
+Metadata-Version: 2.1
 Name: pycurl
-Version: 7.44.1
+Version: 7.45.1
 Summary: PycURL -- A Python Interface To The cURL library
 Home-page: http://pycurl.io/
 Author: Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev
@@ -8,86 +8,6 @@ Author-email: kjetilja@gmail.com, markus
 Maintainer: Oleg Pudeyev
 Maintainer-email: oleg@bsdpower.com
 License: LGPL/MIT
-Description: PycURL -- A Python Interface To The cURL library
-        ================================================
-        
-        PycURL is a Python interface to `libcurl`_, the multiprotocol file
-        transfer library. Similarly to the urllib_ Python module,
-        PycURL can be used to fetch objects identified by a URL from a Python program.
-        Beyond simple fetches however PycURL exposes most of the functionality of
-        libcurl, including:
-        
-        - Speed - libcurl is very fast and PycURL, being a thin wrapper above
-          libcurl, is very fast as well. PycURL `was benchmarked`_ to be several
-          times faster than requests_.
-        - Features including multiple protocol support, SSL, authentication and
-          proxy options. PycURL supports most of libcurl's callbacks.
-        - Multi_ and share_ interfaces.
-        - Sockets used for network operations, permitting integration of PycURL
-          into the application's I/O loop (e.g., using Tornado_).
-        
-        .. _was benchmarked: http://stackoverflow.com/questions/15461995/python-requests-vs-pycurl-performance
-        .. _requests: http://python-requests.org/
-        .. _Multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
-        .. _share: https://curl.haxx.se/libcurl/c/libcurl-share.html
-        .. _Tornado: http://www.tornadoweb.org/
-        
-        
-        Requirements
-        ------------
-        
-        - Python 3.5-3.9.
-        - libcurl 7.19.0 or better.
-        
-        
-        Installation
-        ------------
-        
-        Download the source distribution from `PyPI`_.
-        
-        Please see `the installation documentation`_ for installation instructions.
-        
-        .. _PyPI: https://pypi.python.org/pypi/pycurl
-        .. _the installation documentation: http://pycurl.io/docs/latest/install.html
-        
-        
-        Documentation
-        -------------
-        
-        Documentation for the most recent PycURL release is available on
-        `PycURL website <http://pycurl.io/docs/latest/>`_.
-        
-        
-        Support
-        -------
-        
-        For support questions please use `curl-and-python mailing list`_.
-        `Mailing list archives`_ are available for your perusal as well.
-        
-        Although not an official support venue, `Stack Overflow`_ has been
-        popular with some PycURL users.
-        
-        Bugs can be reported `via GitHub`_. Please use GitHub only for bug
-        reports and direct questions to our mailing list instead.
-        
-        .. _curl-and-python mailing list: http://cool.haxx.se/mailman/listinfo/curl-and-python
-        .. _Stack Overflow: http://stackoverflow.com/questions/tagged/pycurl
-        .. _Mailing list archives: https://curl.haxx.se/mail/list.cgi?list=curl-and-python
-        .. _via GitHub: https://github.com/pycurl/pycurl/issues
-        
-        
-        License
-        -------
-        
-        PycURL is dual licensed under the LGPL and an MIT/X derivative license
-        based on the libcurl license. The complete text of the licenses is available
-        in COPYING-LGPL_ and COPYING-MIT_ files in the source distribution.
-        
-        .. _libcurl: https://curl.haxx.se/libcurl/
-        .. _urllib: http://docs.python.org/library/urllib.html
-        .. _COPYING-LGPL: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-LGPL
-        .. _COPYING-MIT: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-MIT
-        
 Keywords: curl,libcurl,urllib,wget,download,file transfer,http,www
 Platform: All
 Classifier: Development Status :: 5 - Production/Stable
@@ -103,6 +23,92 @@ Classifier: Programming Language :: Pyth
 Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
 Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
 Classifier: Topic :: Internet :: WWW/HTTP
 Requires-Python: >=3.5
+License-File: COPYING-LGPL
+License-File: COPYING-MIT
+License-File: AUTHORS
+
+PycURL -- A Python Interface To The cURL library
+================================================
+
+PycURL is a Python interface to `libcurl`_, the multiprotocol file
+transfer library. Similarly to the urllib_ Python module,
+PycURL can be used to fetch objects identified by a URL from a Python program.
+Beyond simple fetches however PycURL exposes most of the functionality of
+libcurl, including:
+
+- Speed - libcurl is very fast and PycURL, being a thin wrapper above
+  libcurl, is very fast as well. PycURL `was benchmarked`_ to be several
+  times faster than requests_.
+- Features including multiple protocol support, SSL, authentication and
+  proxy options. PycURL supports most of libcurl's callbacks.
+- Multi_ and share_ interfaces.
+- Sockets used for network operations, permitting integration of PycURL
+  into the application's I/O loop (e.g., using Tornado_).
+
+.. _was benchmarked: http://stackoverflow.com/questions/15461995/python-requests-vs-pycurl-performance
+.. _requests: http://python-requests.org/
+.. _Multi: https://curl.haxx.se/libcurl/c/libcurl-multi.html
+.. _share: https://curl.haxx.se/libcurl/c/libcurl-share.html
+.. _Tornado: http://www.tornadoweb.org/
+
+
+Requirements
+------------
+
+- Python 3.5-3.10.
+- libcurl 7.19.0 or better.
+
+
+Installation
+------------
+
+Download the source distribution from `PyPI`_.
+
+Please see `the installation documentation`_ for installation instructions.
+
+.. _PyPI: https://pypi.python.org/pypi/pycurl
+.. _the installation documentation: http://pycurl.io/docs/latest/install.html
+
+
+Documentation
+-------------
+
+Documentation for the most recent PycURL release is available on
+`PycURL website <http://pycurl.io/docs/latest/>`_.
+
+
+Support
+-------
+
+For support questions please use `curl-and-python mailing list`_.
+`Mailing list archives`_ are available for your perusal as well.
+
+Although not an official support venue, `Stack Overflow`_ has been
+popular with some PycURL users.
+
+Bugs can be reported `via GitHub`_. Please use GitHub only for bug
+reports and direct questions to our mailing list instead.
+
+.. _curl-and-python mailing list: http://cool.haxx.se/mailman/listinfo/curl-and-python
+.. _Stack Overflow: http://stackoverflow.com/questions/tagged/pycurl
+.. _Mailing list archives: https://curl.haxx.se/mail/list.cgi?list=curl-and-python
+.. _via GitHub: https://github.com/pycurl/pycurl/issues
+
+
+License
+-------
+
+PycURL is dual licensed under the LGPL and an MIT/X derivative license
+based on the libcurl license. The complete text of the licenses is available
+in COPYING-LGPL_ and COPYING-MIT_ files in the source distribution.
+
+.. _libcurl: https://curl.haxx.se/libcurl/
+.. _urllib: http://docs.python.org/library/urllib.html
+.. _COPYING-LGPL: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-LGPL
+.. _COPYING-MIT: https://raw.githubusercontent.com/pycurl/pycurl/master/COPYING-MIT
+
+
diff -pruN 7.44.1-5/pycurl.egg-info/SOURCES.txt 7.45.1-1/pycurl.egg-info/SOURCES.txt
--- 7.44.1-5/pycurl.egg-info/SOURCES.txt	2021-08-15 19:31:40.000000000 +0000
+++ 7.45.1-1/pycurl.egg-info/SOURCES.txt	2022-03-13 07:13:38.000000000 +0000
@@ -7,6 +7,7 @@ MANIFEST.in
 Makefile
 README.rst
 RELEASE-NOTES.rst
+pytest.ini
 requirements-dev.txt
 setup.py
 winbuild.py
@@ -30,6 +31,7 @@ doc/unicode.rst
 doc/unimplemented.rst
 doc/docstrings/curl.rst
 doc/docstrings/curl_close.rst
+doc/docstrings/curl_duphandle.rst
 doc/docstrings/curl_errstr.rst
 doc/docstrings/curl_errstr_raw.rst
 doc/docstrings/curl_getinfo.rst
@@ -123,6 +125,7 @@ tests/close_socket_cb_test.py
 tests/curl_object_test.py
 tests/debug_test.py
 tests/default_write_cb_test.py
+tests/duphandle_test.py
 tests/error_constants_test.py
 tests/error_test.py
 tests/failonerror_test.py
@@ -137,6 +140,7 @@ tests/info_test.py
 tests/internals_test.py
 tests/matrix.py
 tests/memory_mgmt_test.py
+tests/multi_callback_test.py
 tests/multi_memory_mgmt_test.py
 tests/multi_option_constants_test.py
 tests/multi_socket_select_test.py
@@ -169,6 +173,7 @@ tests/setup_test.py
 tests/share_test.py
 tests/sockopt_cb_test.py
 tests/ssh_key_cb_test.py
+tests/subclass_test.py
 tests/unset_range_test.py
 tests/user_agent_string_test.py
 tests/util.py
diff -pruN 7.44.1-5/pytest.ini 7.45.1-1/pytest.ini
--- 7.44.1-5/pytest.ini	1970-01-01 00:00:00.000000000 +0000
+++ 7.45.1-1/pytest.ini	2021-08-09 01:47:03.000000000 +0000
@@ -0,0 +1,9 @@
+[pytest]
+python_files = tests/*.py
+norecursedirs = examples win
+markers =
+    ssh: mark a test as requiring ssh
+    online: mark a test as requiring internet access
+    gssapi: mark a test as requiring GSSAPI
+    http2: mark a test as requiring HTTP/2
+    standalone: mark a test as being standalone
diff -pruN 7.44.1-5/README.rst 7.45.1-1/README.rst
--- 7.44.1-5/README.rst	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/README.rst	2022-03-09 23:16:18.000000000 +0000
@@ -29,7 +29,7 @@ libcurl, including:
 Requirements
 ------------
 
-- Python 3.5-3.8.
+- Python 3.5-3.10.
 - libcurl 7.19.0 or better.
 
 
@@ -172,7 +172,7 @@ License
 
     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-2021 by Oleg Pudeyev <oleg at bsdpower.com>
+    Copyright (C) 2013-2022 by Oleg Pudeyev <code at olegp.name>
 
     All rights reserved.
 
diff -pruN 7.44.1-5/RELEASE-NOTES.rst 7.45.1-1/RELEASE-NOTES.rst
--- 7.44.1-5/RELEASE-NOTES.rst	2021-08-15 19:30:27.000000000 +0000
+++ 7.45.1-1/RELEASE-NOTES.rst	2022-03-13 07:13:13.000000000 +0000
@@ -1,6 +1,18 @@
 Release Notes
 =============
 
+PycURL 7.45.1 - 2022-03-13
+--------------------------
+
+This release fixes build when libcurl < 7.64.1 is used.
+
+PycURL 7.45.0 - 2022-03-09
+--------------------------
+
+This release adds support for SecureTransport SSL backend (MacOS), adds
+ability to unset a number of multi options, adds ability to duplicate easy
+handles and permits pycurl classes to be subclassed.
+
 PycURL 7.44.1 - 2021-08-15
 --------------------------
 
diff -pruN 7.44.1-5/setup.py 7.45.1-1/setup.py
--- 7.44.1-5/setup.py	2021-08-15 19:30:48.000000000 +0000
+++ 7.45.1-1/setup.py	2022-03-13 07:12:37.000000000 +0000
@@ -6,7 +6,7 @@
 
 PACKAGE = "pycurl"
 PY_PACKAGE = "curl"
-VERSION = "7.44.1"
+VERSION = "7.45.1"
 
 import glob, os, re, sys, subprocess
 import distutils
@@ -145,6 +145,7 @@ class ExtensionConfiguration(object):
             '--with-gnutls': self.using_gnutls,
             '--with-nss': self.using_nss,
             '--with-mbedtls': self.using_mbedtls,
+            '--with-sectransp': self.using_sectransp,
         }
 
     def detect_ssl_option(self):
@@ -162,7 +163,7 @@ class ExtensionConfiguration(object):
 
         if 'PYCURL_SSL_LIBRARY' in os.environ:
             ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
-            if ssl_lib in ['openssl', 'wolfssl', 'gnutls', 'nss', 'mbedtls']:
+            if ssl_lib in ['openssl', 'wolfssl', 'gnutls', 'nss', 'mbedtls', 'sectransp']:
                 ssl_lib_detected = ssl_lib
                 getattr(self, 'using_%s' % ssl_lib)()
             else:
@@ -326,8 +327,9 @@ class ExtensionConfiguration(object):
                 sys.stderr.write('''\
 Warning: libcurl is configured to use SSL, but we have not been able to \
 determine which SSL backend it is using. If your Curl is built against \
-OpenSSL, LibreSSL, BoringSSL, GnuTLS, NSS or mbedTLS please specify the SSL backend \
-manually. For other SSL backends please ignore this message.''')
+OpenSSL, LibreSSL, BoringSSL, GnuTLS, NSS, mbedTLS, or Secure Transport \
+please specify the SSL backend manually. For other SSL backends please \
+ignore this message.''')
         else:
             if self.detect_ssl_option():
                 sys.stderr.write("Warning: SSL backend specified manually but libcurl does not use SSL\n")
@@ -371,6 +373,9 @@ manually. For other SSL backends please
         elif ssl_version.startswith('mbedTLS/'):
             self.using_mbedtls()
             ssl_lib_detected = 'mbedtls'
+        elif ssl_version.startswith('SecureTransport'):
+            self.using_sectransp()
+            ssl_lib_detected = 'sectransp'
         return ssl_lib_detected
 
     def detect_ssl_lib_on_centos6_plus(self):
@@ -411,6 +416,10 @@ manually. For other SSL backends please
         return ssl_lib_detected
 
     def configure_windows(self):
+        OPENSSL_DIR = scan_argv(self.argv, "--openssl-dir=")
+        if OPENSSL_DIR is not None:
+            self.include_dirs.append(os.path.join(OPENSSL_DIR, "include"))
+            self.library_dirs.append(os.path.join(OPENSSL_DIR, "lib"))
         # 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(self.argv, "--curl-dir=")
@@ -572,6 +581,11 @@ manually. For other SSL backends please
         self.define_macros.append(('HAVE_CURL_SSL', 1))
         self.ssl_lib_detected = 'mbedtls'
 
+    def using_sectransp(self):
+        self.define_macros.append(('HAVE_CURL_SECTRANSP', 1))
+        self.define_macros.append(('HAVE_CURL_SSL', 1))
+        self.ssl_lib_detected = 'sectransp'
+
 def get_bdist_msi_version_hack():
     # workaround for distutils/msi version requirement per
     # epydoc.sourceforge.net/stdlib/distutils.version.StrictVersion-class.html -
@@ -610,7 +624,7 @@ def strip_pycurl_options(argv):
     if sys.platform == 'win32':
         options = [
             '--curl-dir=', '--libcurl-lib-name=', '--use-libcurl-dll',
-            '--avoid-stdio', '--with-openssl',
+            '--avoid-stdio', '--with-openssl', '--openssl-dir=',
         ]
     else:
         options = ['--openssl-dir=', '--curl-config=', '--avoid-stdio']
@@ -627,6 +641,7 @@ PRETTY_SSL_LIBS = {
     'gnutls': 'GnuTLS',
     'nss': 'NSS',
     'mbedtls': 'mbedTLS',
+    'sectransp': 'Secure Transport',
 }
 
 def get_extension(argv, split_extension_source=False):
@@ -852,7 +867,7 @@ libcurl, including:
 Requirements
 ------------
 
-- Python 3.5-3.9.
+- Python 3.5-3.10.
 - libcurl 7.19.0 or better.
 
 
@@ -926,6 +941,7 @@ in COPYING-LGPL_ and COPYING-MIT_ files
         'Programming Language :: Python :: 3.7',
         'Programming Language :: Python :: 3.8',
         'Programming Language :: Python :: 3.9',
+        'Programming Language :: Python :: 3.10',
         'Topic :: Internet :: File Transfer Protocol (FTP)',
         'Topic :: Internet :: WWW/HTTP',
     ],
@@ -954,6 +970,7 @@ PycURL Unix options:
  --with-nss                          libcurl is linked against NSS
  --with-mbedtls                      libcurl is linked against mbedTLS
  --with-wolfssl                      libcurl is linked against wolfSSL
+ --with-sectransp                    libcurl is linked against Secure Transport
 '''
 
 windows_help = '''\
@@ -962,6 +979,7 @@ PycURL Windows options:
  --use-libcurl-dll                     link against libcurl DLL, if not given
                                        link against libcurl statically
  --libcurl-lib-name=libcurl_imp.lib    override libcurl import library name
+ --openssl-dir=/path/to/openssl/dir    path to OpenSSL/LibreSSL/BoringSSL headers and libraries
  --with-openssl                        libcurl is linked against OpenSSL/LibreSSL/BoringSSL
  --with-ssl                            legacy alias for --with-openssl
  --link-arg=foo.lib                    also link against specified library
@@ -988,7 +1006,8 @@ if __name__ == "__main__":
     elif len(sys.argv) > 1 and sys.argv[1] == 'docstrings-sources':
         gen_docstrings_sources()
     else:
-        convert_docstrings()
+        if sys.argv[1] not in ['clean'] and (not os.path.exists('src/docstrings.c') or not os.path.exists('src/docstrings.h')):
+            convert_docstrings()
 
         setup_args['data_files'] = get_data_files()
         if 'PYCURL_RELEASE' in os.environ and os.environ['PYCURL_RELEASE'].lower() in ['1', 'yes', 'true']:
diff -pruN 7.44.1-5/src/docstrings.c 7.45.1-1/src/docstrings.c
--- 7.44.1-5/src/docstrings.c	2021-08-15 19:31:40.000000000 +0000
+++ 7.45.1-1/src/docstrings.c	2022-03-09 23:16:42.000000000 +0000
@@ -24,6 +24,30 @@ references to it, but can also be called
 .. _curl_easy_cleanup:\n\
     https://curl.haxx.se/libcurl/c/curl_easy_cleanup.html";
 
+PYCURL_INTERNAL const char curl_duphandle_doc[] = "duphandle() -> Curl\n\
+\n\
+Clone a curl handle. This function will return a new curl handle,\n\
+a duplicate, using all the options previously set in the input curl handle.\n\
+Both handles can subsequently be used independently.\n\
+\n\
+The new handle will not inherit any state information, no connections,\n\
+no SSL sessions and no cookies. It also will not inherit any share object\n\
+states or options (it will be made as if SHARE was unset).\n\
+\n\
+Corresponds to `curl_easy_duphandle`_ in libcurl.\n\
+\n\
+Example usage::\n\
+\n\
+    import pycurl\n\
+    curl = pycurl.Curl()\n\
+    curl.setopt(pycurl.URL, \"https://python.org\")\n\
+    dup = curl.duphandle()\n\
+    curl.perform()\n\
+    dup.perform()\n\
+\n\
+.. _curl_easy_duphandle:\n\
+    https://curl.se/libcurl/c/curl_easy_duphandle.html";
+
 PYCURL_INTERNAL const char curl_errstr_doc[] = "errstr() -> string\n\
 \n\
 Return the internal libcurl error buffer of this handle as a string.\n\
@@ -532,7 +556,7 @@ removes an existing and valid Curl objec
 .. _curl_multi_remove_handle:\n\
     https://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html";
 
-PYCURL_INTERNAL const char multi_select_doc[] = "select([timeout]) -> number of ready file descriptors or -1 on timeout\n\
+PYCURL_INTERNAL const char multi_select_doc[] = "select([timeout]) -> number of ready file descriptors or 0 on timeout\n\
 \n\
 Returns result from doing a select() on the curl multi file descriptor\n\
 with the given timeout.\n\
@@ -552,7 +576,7 @@ Example usage::\n\
         if ret != pycurl.E_CALL_MULTI_PERFORM: break\n\
     while num_handles:\n\
         ret = m.select(1.0)\n\
-        if ret == -1:  continue\n\
+        if ret == 0:  continue\n\
         while 1:\n\
             ret, num_handles = m.perform()\n\
             if ret != pycurl.E_CALL_MULTI_PERFORM: break";
diff -pruN 7.44.1-5/src/docstrings.h 7.45.1-1/src/docstrings.h
--- 7.44.1-5/src/docstrings.h	2021-08-15 19:31:40.000000000 +0000
+++ 7.45.1-1/src/docstrings.h	2022-03-09 23:16:42.000000000 +0000
@@ -3,6 +3,7 @@
 
 extern const char curl_doc[];
 extern const char curl_close_doc[];
+extern const char curl_duphandle_doc[];
 extern const char curl_errstr_doc[];
 extern const char curl_errstr_raw_doc[];
 extern const char curl_getinfo_doc[];
diff -pruN 7.44.1-5/src/easy.c 7.45.1-1/src/easy.c
--- 7.44.1-5/src/easy.c	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/easy.c	2022-03-09 23:12:32.000000000 +0000
@@ -1,6 +1,183 @@
 #include "pycurl.h"
 #include "docstrings.h"
 
+
+/*************************************************************************
+// CurlSlistObject
+**************************************************************************/
+
+PYCURL_INTERNAL void
+util_curlslist_update(CurlSlistObject **old, struct curl_slist *slist)
+{
+    /* Decref previous object */
+    Py_XDECREF(*old);
+    /* Create a new object */
+    *old = PyObject_New(CurlSlistObject, p_CurlSlist_Type);
+    assert(*old != NULL);
+    /* Store curl_slist into the new object */
+    (*old)->slist = slist;
+}
+
+PYCURL_INTERNAL void
+do_curlslist_dealloc(CurlSlistObject *self) {
+    if (self->slist != NULL) {
+        curl_slist_free_all(self->slist);
+        self->slist = NULL;
+    }
+    CurlSlist_Type.tp_free(self);
+}
+
+PYCURL_INTERNAL PyTypeObject CurlSlist_Type = {
+#if PY_MAJOR_VERSION >= 3
+    PyVarObject_HEAD_INIT(NULL, 0)
+#else
+    PyObject_HEAD_INIT(NULL)
+    0,                          /* ob_size */
+#endif
+    "pycurl.CurlSlist",         /* tp_name */
+    sizeof(CurlSlistObject),    /* tp_basicsize */
+    0,                          /* tp_itemsize */
+    (destructor)do_curlslist_dealloc, /* tp_dealloc */
+    0,                          /* tp_print / tp_vectorcall_offset */
+    0,                          /* tp_getattr */
+    0,                          /* tp_setattr */
+    0,                          /* tp_reserved / tp_as_async */
+    0,                          /* tp_repr */
+    0,                          /* tp_as_number */
+    0,                          /* tp_as_sequence */
+    0,                          /* tp_as_mapping */
+    0,                          /* tp_hash */
+    0,                          /* tp_call */
+    0,                          /* tp_str */
+    0,                          /* tp_getattro */
+    0,                          /* tp_setattro */
+    0,                          /* tp_as_buffer */
+    0,                          /* tp_flags */
+    0,                          /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    0,                          /* tp_methods */
+    0,                          /* tp_members */
+    0,                          /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+#if PY_MAJOR_VERSION >= 3
+    0,                          /* tp_del */
+    0,                          /* tp_version_tag */
+    0,                          /* tp_finalize */
+#if PY_VERSION_HEX >= 0x03080000
+    0,                          /* tp_vectorcall */
+#endif
+#endif
+};
+
+
+/*************************************************************************
+// CurlHttppostObject
+**************************************************************************/
+
+PYCURL_INTERNAL void
+util_curlhttppost_update(CurlObject *obj, struct curl_httppost *httppost, PyObject *reflist)
+{
+    /* Decref previous object */
+    Py_XDECREF(obj->httppost);
+    /* Create a new object */
+    obj->httppost = PyObject_New(CurlHttppostObject, p_CurlHttppost_Type);
+    assert(obj->httppost != NULL);
+    /* Store curl_httppost and reflist into the new object */
+    obj->httppost->httppost = httppost;
+    obj->httppost->reflist = reflist;
+}
+
+PYCURL_INTERNAL void
+do_curlhttppost_dealloc(CurlHttppostObject *self) {
+    if (self->httppost != NULL) {
+        curl_formfree(self->httppost);
+        self->httppost = NULL;
+    }
+    Py_CLEAR(self->reflist);
+    CurlHttppost_Type.tp_free(self);
+}
+
+PYCURL_INTERNAL PyTypeObject CurlHttppost_Type = {
+#if PY_MAJOR_VERSION >= 3
+    PyVarObject_HEAD_INIT(NULL, 0)
+#else
+    PyObject_HEAD_INIT(NULL)
+    0,                          /* ob_size */
+#endif
+    "pycurl.CurlHttppost",      /* tp_name */
+    sizeof(CurlHttppostObject), /* tp_basicsize */
+    0,                          /* tp_itemsize */
+    (destructor)do_curlhttppost_dealloc, /* tp_dealloc */
+    0,                          /* tp_print / tp_vectorcall_offset */
+    0,                          /* tp_getattr */
+    0,                          /* tp_setattr */
+    0,                          /* tp_reserved / tp_as_async */
+    0,                          /* tp_repr */
+    0,                          /* tp_as_number */
+    0,                          /* tp_as_sequence */
+    0,                          /* tp_as_mapping */
+    0,                          /* tp_hash */
+    0,                          /* tp_call */
+    0,                          /* tp_str */
+    0,                          /* tp_getattro */
+    0,                          /* tp_setattro */
+    0,                          /* tp_as_buffer */
+    0,                          /* tp_flags */
+    0,                          /* tp_doc */
+    0,                          /* tp_traverse */
+    0,                          /* tp_clear */
+    0,                          /* tp_richcompare */
+    0,                          /* tp_weaklistoffset */
+    0,                          /* tp_iter */
+    0,                          /* tp_iternext */
+    0,                          /* tp_methods */
+    0,                          /* tp_members */
+    0,                          /* tp_getset */
+    0,                          /* tp_base */
+    0,                          /* tp_dict */
+    0,                          /* tp_descr_get */
+    0,                          /* tp_descr_set */
+    0,                          /* tp_dictoffset */
+    0,                          /* tp_init */
+    0,                          /* tp_alloc */
+    0,                          /* tp_new */
+    0,                          /* tp_free */
+    0,                          /* tp_is_gc */
+    0,                          /* tp_bases */
+    0,                          /* tp_mro */
+    0,                          /* tp_cache */
+    0,                          /* tp_subclasses */
+    0,                          /* tp_weaklist */
+#if PY_MAJOR_VERSION >= 3
+    0,                          /* tp_del */
+    0,                          /* tp_version_tag */
+    0,                          /* tp_finalize */
+#if PY_VERSION_HEX >= 0x03080000
+    0,                          /* tp_vectorcall */
+#endif
+#endif
+};
+
+
 /*************************************************************************
 // static utility functions
 **************************************************************************/
@@ -11,7 +188,7 @@ PYCURL_INTERNAL void
 assert_curl_state(const CurlObject *self)
 {
     assert(self != NULL);
-    assert(Py_TYPE(self) == p_Curl_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_Curl_Type) == 1);
 #ifdef WITH_THREAD
     (void) pycurl_get_thread_state(self);
 #endif
@@ -91,12 +268,12 @@ do_curl_new(PyTypeObject *subtype, PyObj
     int res;
     int *ptr;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
+    if (subtype == p_Curl_Type && !PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
         return NULL;
     }
 
     /* Allocate python curl object */
-    self = (CurlObject *) p_Curl_Type->tp_alloc(p_Curl_Type, 0);
+    self = (CurlObject *) subtype->tp_alloc(subtype, 0);
     if (self == NULL)
         return NULL;
 
@@ -123,6 +300,156 @@ error:
     return NULL;
 }
 
+/* duphandle */
+PYCURL_INTERNAL CurlObject *
+do_curl_duphandle(CurlObject *self)
+{
+    PyTypeObject *subtype;
+    CurlObject *dup;
+    int res;
+    int *ptr;
+
+    /* Allocate python curl object */
+    subtype = Py_TYPE(self);
+    dup = (CurlObject *) subtype->tp_alloc(subtype, 0);
+    if (dup == NULL)
+        return NULL;
+
+    /* tp_alloc is expected to return zeroed memory */
+    for (ptr = (int *) &dup->dict;
+        ptr < (int *) (((char *) dup) + sizeof(CurlObject));
+        ++ptr)
+            assert(*ptr == 0);
+
+    /* Clone the curl handle */
+    dup->handle = curl_easy_duphandle(self->handle);
+    if (dup->handle == NULL)
+        goto error;
+
+    /* Set curl error buffer and zero it */
+    res = curl_easy_setopt(dup->handle, CURLOPT_ERRORBUFFER, dup->error);
+    if (res != CURLE_OK) {
+        goto error;
+    }
+    memset(dup->error, 0, sizeof(dup->error));
+
+    /* Set backreference */
+    res = curl_easy_setopt(dup->handle, CURLOPT_PRIVATE, (char *) dup);
+    if (res != CURLE_OK) {
+        goto error;
+    }
+
+    /* Copy attribute dictionary */
+    if (self->dict != NULL) {
+        dup->dict = PyDict_Copy(self->dict);
+        if (dup->dict == NULL) {
+            goto error;
+        }
+    }
+
+    /* Checking for CURLE_OK is not required here.
+     * All values have already been successfuly setopt'ed with self->handle. */
+
+    /* Assign and incref python callback and update data pointers */
+    if (self->w_cb != NULL) {
+        dup->w_cb = my_Py_NewRef(self->w_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_WRITEDATA, dup);
+    }
+    if (self->h_cb != NULL) {
+        dup->h_cb = my_Py_NewRef(self->h_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_WRITEHEADER, dup);
+    }
+    if (self->r_cb != NULL) {
+        dup->r_cb = my_Py_NewRef(self->r_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_READDATA, dup);
+    }
+    if (self->pro_cb != NULL) {
+        dup->pro_cb = my_Py_NewRef(self->pro_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_PROGRESSDATA, dup);
+    }
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
+    if (self->xferinfo_cb != NULL) {
+        dup->xferinfo_cb = my_Py_NewRef(self->xferinfo_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_XFERINFODATA, dup);
+    }
+#endif
+    if (self->debug_cb != NULL) {
+        dup->debug_cb = my_Py_NewRef(self->debug_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_DEBUGDATA, dup);
+    }
+    if (self->ioctl_cb != NULL) {
+        dup->ioctl_cb = my_Py_NewRef(self->ioctl_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_IOCTLDATA, dup);
+    }
+    if (self->opensocket_cb != NULL) {
+        dup->opensocket_cb = my_Py_NewRef(self->opensocket_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_OPENSOCKETDATA, dup);
+    }
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
+    if (self->closesocket_cb != NULL) {
+        dup->closesocket_cb = my_Py_NewRef(self->closesocket_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_CLOSESOCKETDATA, dup);
+    }
+#endif
+    if (self->sockopt_cb != NULL) {
+        dup->sockopt_cb = my_Py_NewRef(self->sockopt_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_SOCKOPTDATA, dup);
+    }
+#ifdef HAVE_CURL_7_19_6_OPTS
+    if (self->ssh_key_cb != NULL) {
+        dup->ssh_key_cb = my_Py_NewRef(self->ssh_key_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_SSH_KEYDATA, dup);
+    }
+#endif
+    if (self->seek_cb != NULL) {
+        dup->seek_cb = my_Py_NewRef(self->seek_cb);
+        curl_easy_setopt(dup->handle, CURLOPT_SEEKDATA, dup);
+    }
+
+    /* Assign and incref python file objects */
+    dup->readdata_fp = my_Py_XNewRef(self->readdata_fp);
+    dup->writedata_fp = my_Py_XNewRef(self->writedata_fp);
+    dup->writeheader_fp = my_Py_XNewRef(self->writeheader_fp);
+
+    /* Assign and incref postfields object */
+    dup->postfields_obj = my_Py_XNewRef(self->postfields_obj);
+
+    /* Assign and incref ca certs related references */
+    dup->ca_certs_obj = my_Py_XNewRef(self->ca_certs_obj);
+
+    /* Assign and incref every curl_slist allocated by setopt */
+    dup->httpheader = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+    dup->proxyheader = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->proxyheader);
+#endif
+    dup->http200aliases = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->http200aliases);
+    dup->quote = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->quote);
+    dup->postquote = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->postquote);
+    dup->prequote = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->prequote);
+    dup->telnetoptions = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+    dup->resolve = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+    dup->mail_rcpt = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+    dup->connect_to = (CurlSlistObject *)my_Py_XNewRef((PyObject *)self->connect_to);
+#endif
+
+    /* Assign and incref httppost */
+    dup->httppost = (CurlHttppostObject *)my_Py_XNewRef((PyObject *)self->httppost);
+
+    /* Success - return cloned object */
+    return dup;
+
+error:
+    Py_CLEAR(dup->dict);
+    Py_DECREF(dup);    /* this also closes dup->handle */
+    PyErr_SetString(ErrorObject, "cloning curl failed");
+    return NULL;
+}
+
 
 /* util function shared by close() and clear() */
 PYCURL_INTERNAL void
@@ -137,14 +464,17 @@ util_curl_xdecref(CurlObject *self, int
         /* Decrement refcount for multi_stack. */
         if (self->multi_stack != NULL) {
             CurlMultiObject *multi_stack = self->multi_stack;
-            self->multi_stack = NULL;
             if (multi_stack->multi_handle != NULL && handle != NULL) {
                 /* TODO this is where we could remove the easy object
                 from the multi object's easy_object_dict, but this
                 requires us to have a reference to the multi object
                 which right now we don't. */
+                /* Allow threads because callbacks can be invoked */
+                PYCURL_BEGIN_ALLOW_THREADS_EASY
                 (void) curl_multi_remove_handle(multi_stack->multi_handle, handle);
+                PYCURL_END_ALLOW_THREADS_EASY
             }
+            self->multi_stack = NULL;
             Py_DECREF(multi_stack);
         }
     }
@@ -194,14 +524,36 @@ util_curl_xdecref(CurlObject *self, int
     }
 
     if (flags & PYCURL_MEMGROUP_HTTPPOST) {
-        /* Decrement refcounts for httppost related references. */
-        Py_CLEAR(self->httppost_ref_list);
+        /* Decrement refcounts for httppost object. */
+        Py_CLEAR(self->httppost);
     }
 
     if (flags & PYCURL_MEMGROUP_CACERTS) {
         /* Decrement refcounts for ca certs related references. */
         Py_CLEAR(self->ca_certs_obj);
     }
+
+    if (flags & PYCURL_MEMGROUP_SLIST) {
+        /* Decrement refcounts for slist objects. */
+        Py_CLEAR(self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+        Py_CLEAR(self->proxyheader);
+#endif
+        Py_CLEAR(self->http200aliases);
+        Py_CLEAR(self->quote);
+        Py_CLEAR(self->postquote);
+        Py_CLEAR(self->prequote);
+        Py_CLEAR(self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+        Py_CLEAR(self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+        Py_CLEAR(self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+        Py_CLEAR(self->connect_to);
+#endif
+    }
 }
 
 
@@ -213,7 +565,7 @@ util_curl_close(CurlObject *self)
     /* Zero handle and thread-state to disallow any operations to be run
      * from now on */
     assert(self != NULL);
-    assert(Py_TYPE(self) == p_Curl_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_Curl_Type) == 1);
     handle = self->handle;
     self->handle = NULL;
     if (handle == NULL) {
@@ -247,32 +599,6 @@ util_curl_close(CurlObject *self)
     if (self->weakreflist != NULL) {
         PyObject_ClearWeakRefs((PyObject *) self);
     }
-
-    /* Free all variables allocated by setopt */
-#undef SFREE
-#define SFREE(v)   if ((v) != NULL) (curl_formfree(v), (v) = NULL)
-    SFREE(self->httppost);
-#undef SFREE
-#define SFREE(v)   if ((v) != NULL) (curl_slist_free_all(v), (v) = NULL)
-    SFREE(self->httpheader);
-#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
-    SFREE(self->proxyheader);
-#endif
-    SFREE(self->http200aliases);
-    SFREE(self->quote);
-    SFREE(self->postquote);
-    SFREE(self->prequote);
-    SFREE(self->telnetoptions);
-#ifdef HAVE_CURLOPT_RESOLVE
-    SFREE(self->resolve);
-#endif
-#ifdef HAVE_CURL_7_20_0_OPTS
-    SFREE(self->mail_rcpt);
-#endif
-#ifdef HAVE_CURLOPT_CONNECT_TO
-    SFREE(self->connect_to);
-#endif
-#undef SFREE
 }
 
 
@@ -351,6 +677,27 @@ do_curl_traverse(CurlObject *self, visit
 
     VISIT(self->ca_certs_obj);
 
+    VISIT((PyObject *) self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+    VISIT((PyObject *) self->proxyheader);
+#endif
+    VISIT((PyObject *) self->http200aliases);
+    VISIT((PyObject *) self->quote);
+    VISIT((PyObject *) self->postquote);
+    VISIT((PyObject *) self->prequote);
+    VISIT((PyObject *) self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+    VISIT((PyObject *) self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+    VISIT((PyObject *) self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+    VISIT((PyObject *) self->connect_to);
+#endif
+
+    VISIT((PyObject *) self->httppost);
+
     return 0;
 #undef VISIT
 }
@@ -368,31 +715,6 @@ do_curl_reset(CurlObject *self)
     /* Decref easy interface related objects */
     util_curl_xdecref(self, PYCURL_MEMGROUP_EASY, self->handle);
 
-    /* Free all variables allocated by setopt */
-#undef SFREE
-#define SFREE(v)   if ((v) != NULL) (curl_formfree(v), (v) = NULL)
-    SFREE(self->httppost);
-#undef SFREE
-#define SFREE(v)   if ((v) != NULL) (curl_slist_free_all(v), (v) = NULL)
-    SFREE(self->httpheader);
-#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
-    SFREE(self->proxyheader);
-#endif
-    SFREE(self->http200aliases);
-    SFREE(self->quote);
-    SFREE(self->postquote);
-    SFREE(self->prequote);
-    SFREE(self->telnetoptions);
-#ifdef HAVE_CURLOPT_RESOLVE
-    SFREE(self->resolve);
-#endif
-#ifdef HAVE_CURL_7_20_0_OPTS
-    SFREE(self->mail_rcpt);
-#endif
-#ifdef HAVE_CURLOPT_CONNECT_TO
-    SFREE(self->connect_to);
-#endif
-#undef SFREE
     res = util_curl_init(self);
     if (res < 0) {
         Py_DECREF(self);    /* this also closes self->handle */
@@ -438,6 +760,7 @@ PYCURL_INTERNAL PyMethodDef curlobject_m
     {"setopt_string", (PyCFunction)do_curl_setopt_string, METH_VARARGS, curl_setopt_string_doc},
     {"unsetopt", (PyCFunction)do_curl_unsetopt, METH_VARARGS, curl_unsetopt_doc},
     {"reset", (PyCFunction)do_curl_reset, METH_NOARGS, curl_reset_doc},
+    {"duphandle", (PyCFunction)do_curl_duphandle, METH_NOARGS, curl_duphandle_doc},
 #if defined(HAVE_CURL_OPENSSL)
     {"set_ca_certs", (PyCFunction)do_curl_set_ca_certs, METH_VARARGS, curl_set_ca_certs_doc},
 #endif
diff -pruN 7.44.1-5/src/easyopt.c 7.45.1-1/src/easyopt.c
--- 7.44.1-5/src/easyopt.c	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/easyopt.c	2022-01-11 19:34:56.000000000 +0000
@@ -46,6 +46,12 @@ util_curl_unsetopt(CurlObject *self, int
 #define SETOPT2(o,x) \
     if ((res = curl_easy_setopt(self->handle, (o), (x))) != CURLE_OK) goto error
 #define SETOPT(x)   SETOPT2((CURLoption)option, (x))
+#define CLEAR_OBJECT(object_option, object_field) \
+    case object_option: \
+        if ((res = curl_easy_setopt(self->handle, object_option, NULL)) != CURLE_OK) \
+            goto error; \
+        Py_CLEAR(object_field); \
+        break
 #define CLEAR_CALLBACK(callback_option, data_option, callback_field) \
     case callback_option: \
         if ((res = curl_easy_setopt(self->handle, callback_option, NULL)) != CURLE_OK) \
@@ -65,13 +71,6 @@ util_curl_unsetopt(CurlObject *self, int
         Py_XDECREF(self->share);
         self->share = NULL;
         break;
-    case CURLOPT_HTTPPOST:
-        SETOPT((void *) 0);
-        curl_formfree(self->httppost);
-        util_curl_xdecref(self, PYCURL_MEMGROUP_HTTPPOST, self->handle);
-        self->httppost = NULL;
-        /* FIXME: what about data->set.httpreq ?? */
-        break;
     case CURLOPT_INFILESIZE:
         SETOPT((long) -1);
         break;
@@ -108,10 +107,6 @@ util_curl_unsetopt(CurlObject *self, int
     case CURLOPT_SERVICE_NAME:
     case CURLOPT_PROXY_SERVICE_NAME:
 #endif
-    case CURLOPT_HTTPHEADER:
-#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
-    case CURLOPT_PROXYHEADER:
-#endif
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
     case CURLOPT_PROXY_CAPATH:
     case CURLOPT_PROXY_CAINFO:
@@ -130,6 +125,27 @@ util_curl_unsetopt(CurlObject *self, int
         break;
 #endif
 
+    CLEAR_OBJECT(CURLOPT_HTTPHEADER, self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+    CLEAR_OBJECT(CURLOPT_PROXYHEADER, self->proxyheader);
+#endif
+    CLEAR_OBJECT(CURLOPT_HTTP200ALIASES, self->http200aliases);
+    CLEAR_OBJECT(CURLOPT_QUOTE, self->quote);
+    CLEAR_OBJECT(CURLOPT_POSTQUOTE, self->postquote);
+    CLEAR_OBJECT(CURLOPT_PREQUOTE, self->prequote);
+    CLEAR_OBJECT(CURLOPT_TELNETOPTIONS, self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+    CLEAR_OBJECT(CURLOPT_RESOLVE, self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+    CLEAR_OBJECT(CURLOPT_MAIL_RCPT, self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+    CLEAR_OBJECT(CURLOPT_CONNECT_TO, self->connect_to);
+#endif
+    /* FIXME: what about data->set.httpreq ?? */
+    CLEAR_OBJECT(CURLOPT_HTTPPOST, self->httppost);
+
     CLEAR_CALLBACK(CURLOPT_OPENSOCKETFUNCTION, CURLOPT_OPENSOCKETDATA, self->opensocket_cb);
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
     CLEAR_CALLBACK(CURLOPT_CLOSESOCKETFUNCTION, CURLOPT_CLOSESOCKETDATA, self->closesocket_cb);
@@ -690,16 +706,9 @@ do_curl_setopt_httppost(CurlObject *self
         CURLERROR_SET_RETVAL();
         goto error;
     }
-    /* Finally, free previously allocated httppost, ZAP any
-     * buffer references, and update */
-    curl_formfree(self->httppost);
-    util_curl_xdecref(self, PYCURL_MEMGROUP_HTTPPOST, self->handle);
-    self->httppost = post;
-
-    /* The previous list of INCed references was ZAPed above; save
-     * the new one so that we can clean it up on the next
-     * self->httppost free. */
-    self->httppost_ref_list = ref_params;
+    /* Finally, decref previous httppost object and replace it with a
+     * new one. */
+    util_curlhttppost_update(self, post, ref_params);
 
     Py_RETURN_NONE;
 
@@ -713,48 +722,48 @@ error:
 static PyObject *
 do_curl_setopt_list(CurlObject *self, int option, int which, PyObject *obj)
 {
-    struct curl_slist **old_slist = NULL;
+    CurlSlistObject **old_slist_obj = NULL;
     struct curl_slist *slist = NULL;
     Py_ssize_t len;
     int res;
 
     switch (option) {
     case CURLOPT_HTTP200ALIASES:
-        old_slist = &self->http200aliases;
+        old_slist_obj = &self->http200aliases;
         break;
     case CURLOPT_HTTPHEADER:
-        old_slist = &self->httpheader;
+        old_slist_obj = &self->httpheader;
         break;
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
     case CURLOPT_PROXYHEADER:
-        old_slist = &self->proxyheader;
+        old_slist_obj = &self->proxyheader;
         break;
 #endif
     case CURLOPT_POSTQUOTE:
-        old_slist = &self->postquote;
+        old_slist_obj = &self->postquote;
         break;
     case CURLOPT_PREQUOTE:
-        old_slist = &self->prequote;
+        old_slist_obj = &self->prequote;
         break;
     case CURLOPT_QUOTE:
-        old_slist = &self->quote;
+        old_slist_obj = &self->quote;
         break;
     case CURLOPT_TELNETOPTIONS:
-        old_slist = &self->telnetoptions;
+        old_slist_obj = &self->telnetoptions;
         break;
 #ifdef HAVE_CURLOPT_RESOLVE
     case CURLOPT_RESOLVE:
-        old_slist = &self->resolve;
+        old_slist_obj = &self->resolve;
         break;
 #endif
 #ifdef HAVE_CURL_7_20_0_OPTS
     case CURLOPT_MAIL_RCPT:
-        old_slist = &self->mail_rcpt;
+        old_slist_obj = &self->mail_rcpt;
         break;
 #endif
 #ifdef HAVE_CURLOPT_CONNECT_TO
     case CURLOPT_CONNECT_TO:
-        old_slist = &self->connect_to;
+        old_slist_obj = &self->connect_to;
         break;
 #endif
     default:
@@ -768,7 +777,7 @@ do_curl_setopt_list(CurlObject *self, in
         Py_RETURN_NONE;
 
     /* Just to be sure we do not bug off here */
-    assert(old_slist != NULL && slist == NULL);
+    assert(old_slist_obj != NULL && slist == NULL);
 
     /* Handle regular list operations on the other options */
     slist = pycurl_list_or_tuple_to_slist(which, obj, len);
@@ -781,9 +790,9 @@ do_curl_setopt_list(CurlObject *self, in
         curl_slist_free_all(slist);
         CURLERROR_RETVAL();
     }
-    /* Finally, free previously allocated list and update */
-    curl_slist_free_all(*old_slist);
-    *old_slist = slist;
+    /* Finally, decref previous slist object and replace it with a
+     * new one. */
+    util_curlslist_update(old_slist_obj, slist);
 
     Py_RETURN_NONE;
 }
diff -pruN 7.44.1-5/src/easyperform.c 7.45.1-1/src/easyperform.c
--- 7.44.1-5/src/easyperform.c	2021-08-15 19:21:50.000000000 +0000
+++ 7.45.1-1/src/easyperform.c	2022-01-11 19:34:56.000000000 +0000
@@ -100,7 +100,7 @@ do_curl_pause(CurlObject *self, PyObject
 #ifdef WITH_THREAD
     /* Save handle to current thread (used as context for python callbacks) */
     saved_state = self->state;
-    PYCURL_BEGIN_ALLOW_THREADS
+    PYCURL_BEGIN_ALLOW_THREADS_EASY
 
     /* We must allow threads here because unpausing a handle can cause
        some of its callbacks to be invoked immediately, from inside
@@ -110,7 +110,7 @@ do_curl_pause(CurlObject *self, PyObject
     res = curl_easy_pause(self->handle, bitmask);
 
 #ifdef WITH_THREAD
-    PYCURL_END_ALLOW_THREADS
+    PYCURL_END_ALLOW_THREADS_EASY
 
     /* Restore the thread-state to whatever it was on entry */
     self->state = saved_state;
diff -pruN 7.44.1-5/src/module.c 7.45.1-1/src/module.c
--- 7.44.1-5/src/module.c	2021-08-15 19:21:52.000000000 +0000
+++ 7.45.1-1/src/module.c	2022-03-13 07:10:38.000000000 +0000
@@ -28,6 +28,8 @@ PYCURL_INTERNAL char *g_pycurl_useragent
 /* Type objects */
 PYCURL_INTERNAL PyObject *ErrorObject = NULL;
 PYCURL_INTERNAL PyTypeObject *p_Curl_Type = NULL;
+PYCURL_INTERNAL PyTypeObject *p_CurlSlist_Type = NULL;
+PYCURL_INTERNAL PyTypeObject *p_CurlHttppost_Type = NULL;
 PYCURL_INTERNAL PyTypeObject *p_CurlMulti_Type = NULL;
 PYCURL_INTERNAL PyTypeObject *p_CurlShare_Type = NULL;
 #ifdef HAVE_CURL_7_19_6_OPTS
@@ -374,6 +376,11 @@ initpycurl(void)
                 case CURLSSLBACKEND_NSS:
                 case CURLSSLBACKEND_WOLFSSL:
                 case CURLSSLBACKEND_MBEDTLS:
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 64, 1)
+                case CURLSSLBACKEND_SECURETRANSPORT:
+#else
+                case CURLSSLBACKEND_DARWINSSL:
+#endif
                     runtime_supported_backend_found = 1;
                     break;
                 default:
@@ -404,6 +411,8 @@ initpycurl(void)
         runtime_ssl_lib = "nss";
     } else if (!strncmp(vi->ssl_version, "mbedTLS/", 8)) {
         runtime_ssl_lib = "mbedtls";
+    } else if (!strncmp(vi->ssl_version, "Secure Transport", 16)) {
+        runtime_ssl_lib = "secure-transport";
     } else {
         runtime_ssl_lib = "none/other";
     }
@@ -416,9 +425,13 @@ initpycurl(void)
     /* Initialize the type of the new type objects here; doing it here
      * is required for portability to Windows without requiring C++. */
     p_Curl_Type = &Curl_Type;
+    p_CurlSlist_Type = &CurlSlist_Type;
+    p_CurlHttppost_Type = &CurlHttppost_Type;
     p_CurlMulti_Type = &CurlMulti_Type;
     p_CurlShare_Type = &CurlShare_Type;
     Py_SET_TYPE(&Curl_Type, &PyType_Type);
+    Py_SET_TYPE(&CurlSlist_Type, &PyType_Type);
+    Py_SET_TYPE(&CurlHttppost_Type, &PyType_Type);
     Py_SET_TYPE(&CurlMulti_Type, &PyType_Type);
     Py_SET_TYPE(&CurlShare_Type, &PyType_Type);
 
@@ -426,12 +439,19 @@ initpycurl(void)
     if (PyType_Ready(&Curl_Type) < 0)
         goto error;
 
+    if (PyType_Ready(&CurlSlist_Type) < 0)
+        goto error;
+
+    if (PyType_Ready(&CurlHttppost_Type) < 0)
+        goto error;
+
     if (PyType_Ready(&CurlMulti_Type) < 0)
         goto error;
 
     if (PyType_Ready(&CurlShare_Type) < 0)
         goto error;
 
+
 #if PY_MAJOR_VERSION >= 3
     m = PyModule_Create(&curlmodule);
     if (m == NULL)
@@ -1060,6 +1080,9 @@ initpycurl(void)
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 62, 0)
     insint_c(d, "DOH_URL", CURLOPT_DOH_URL);
 #endif
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 80, 0)
+    insint_c(d, "MAXLIFETIME_CONN", CURLOPT_MAXLIFETIME_CONN);
+#endif
 
     insint_m(d, "M_TIMERFUNCTION", CURLMOPT_TIMERFUNCTION);
     insint_m(d, "M_SOCKETFUNCTION", CURLMOPT_SOCKETFUNCTION);
@@ -1430,6 +1453,9 @@ initpycurl(void)
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 57, 0)
     insint_s(d, "LOCK_DATA_CONNECT", CURL_LOCK_DATA_CONNECT);
 #endif
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 61, 0)
+    insint_s(d, "LOCK_DATA_PSL", CURL_LOCK_DATA_PSL);
+#endif
 
     /* Initialize callback locks if ssl is enabled */
 #if defined(PYCURL_NEED_SSL_TSL)
diff -pruN 7.44.1-5/src/multi.c 7.45.1-1/src/multi.c
--- 7.44.1-5/src/multi.c	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/multi.c	2022-01-11 19:34:56.000000000 +0000
@@ -11,7 +11,7 @@ static void
 assert_multi_state(const CurlMultiObject *self)
 {
     assert(self != NULL);
-    assert(Py_TYPE(self) == p_CurlMulti_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_CurlMulti_Type) == 1);
 #ifdef WITH_THREAD
     if (self->state != NULL) {
         assert(self->multi_handle != NULL);
@@ -51,12 +51,12 @@ do_multi_new(PyTypeObject *subtype, PyOb
     CurlMultiObject *self;
     int *ptr;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
+    if (subtype == p_CurlMulti_Type && !PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
         return NULL;
     }
 
     /* Allocate python curl-multi object */
-    self = (CurlMultiObject *) p_CurlMulti_Type->tp_alloc(p_CurlMulti_Type, 0);
+    self = (CurlMultiObject *) subtype->tp_alloc(subtype, 0);
     if (!self) {
         return NULL;
     }
@@ -94,11 +94,11 @@ util_multi_close(CurlMultiObject *self)
     
     if (self->multi_handle != NULL) {
         CURLM *multi_handle = self->multi_handle;
-        self->multi_handle = NULL;
         /* Allow threads because callbacks can be invoked */
         PYCURL_BEGIN_ALLOW_THREADS
         curl_multi_cleanup(multi_handle);
         PYCURL_END_ALLOW_THREADS
+        self->multi_handle = NULL;
     }
 }
 
@@ -183,8 +183,12 @@ multi_socket_callback(CURL *easy,
 
     /* acquire thread */
     self = (CurlMultiObject *)userp;
-    if (!PYCURL_ACQUIRE_THREAD_MULTI())
+    if (!PYCURL_ACQUIRE_THREAD_MULTI()) {
+        PyGILState_STATE tmp_warn_state = PyGILState_Ensure();
+        PyErr_WarnEx(PyExc_RuntimeWarning, "multi_socket_callback failed to acquire thread", 1);
+        PyGILState_Release(tmp_warn_state);
         return 0;
+    }
 
     /* check args */
     if (self->s_cb == NULL)
@@ -232,8 +236,12 @@ multi_timer_callback(CURLM *multi,
 
     /* acquire thread */
     self = (CurlMultiObject *)userp;
-    if (!PYCURL_ACQUIRE_THREAD_MULTI())
+    if (!PYCURL_ACQUIRE_THREAD_MULTI()) {
+        PyGILState_STATE tmp_warn_state = PyGILState_Ensure();
+        PyErr_WarnEx(PyExc_RuntimeWarning, "multi_timer_callback failed to acquire thread", 1);
+        PyGILState_Release(tmp_warn_state);
         return ret;
+    }
 
     /* check args */
     if (self->t_cb == NULL)
@@ -407,6 +415,34 @@ do_multi_setopt_callable(CurlMultiObject
 
 
 static PyObject *
+do_multi_setopt_none(CurlMultiObject *self, int option, PyObject *obj)
+{
+    switch(option) {
+#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
+    case CURLMOPT_PIPELINING_SITE_BL:
+    case CURLMOPT_PIPELINING_SERVER_BL:
+        curl_multi_setopt(self->multi_handle, option, NULL);
+        break;
+#endif
+    case CURLMOPT_SOCKETFUNCTION:
+        curl_multi_setopt(self->multi_handle, CURLMOPT_SOCKETFUNCTION, NULL);
+        curl_multi_setopt(self->multi_handle, CURLMOPT_SOCKETDATA, NULL);
+        Py_CLEAR(self->s_cb);
+        break;
+    case CURLMOPT_TIMERFUNCTION:
+        curl_multi_setopt(self->multi_handle, CURLMOPT_TIMERFUNCTION, NULL);
+        curl_multi_setopt(self->multi_handle, CURLMOPT_TIMERDATA, NULL);
+        Py_CLEAR(self->t_cb);
+        break;
+    default:
+        PyErr_SetString(PyExc_TypeError, "unsetting is not supported for this option");
+        return NULL;
+    }
+    Py_RETURN_NONE;
+}
+
+
+static PyObject *
 do_multi_setopt(CurlMultiObject *self, PyObject *args)
 {
     int option, which;
@@ -425,6 +461,11 @@ do_multi_setopt(CurlMultiObject *self, P
     if (option % 10000 >= MOPTIONS_SIZE)
         goto error;
 
+    /* Handle unsetting of options */
+    if (obj == Py_None) {
+        return do_multi_setopt_none(self, option, obj);
+    }
+
     /* Handle the case of integer arguments */
     if (PyInt_Check(obj)) {
         return do_multi_setopt_int(self, option, obj);
@@ -797,7 +838,7 @@ do_multi_info_read(CurlMultiObject *self
             Py_DECREF(ok_list);
             CURLERROR_MSG("Unable to fetch curl handle from curl object");
         }
-        assert(Py_TYPE(co) == p_Curl_Type);
+        assert(PyObject_IsInstance((PyObject *) co, (PyObject *) p_Curl_Type) == 1);
         if (msg->msg != CURLMSG_DONE) {
             /* FIXME: what does this mean ??? */
         }
diff -pruN 7.44.1-5/src/pycurl.h 7.45.1-1/src/pycurl.h
--- 7.44.1-5/src/pycurl.h	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/pycurl.h	2022-01-11 19:34:56.000000000 +0000
@@ -220,6 +220,9 @@ pycurl_inet_ntop (int family, void *addr
 #   define PYCURL_NEED_MBEDTLS_TSL
 #   define COMPILE_SSL_LIB "mbedtls"
 #   define COMPILE_SUPPORTED_SSL_BACKEND_FOUND 1
+# elif defined(HAVE_CURL_SECTRANSP)
+#   define COMPILE_SSL_LIB "secure-transport"
+#   define COMPILE_SUPPORTED_SSL_BACKEND_FOUND 1
 # else
 #  ifdef _MSC_VER
     /* sigh */
@@ -237,7 +240,7 @@ pycurl_inet_ntop (int family, void *addr
     * no reason to require users match those */
 #  define COMPILE_SSL_LIB "none/other"
 #  define COMPILE_SUPPORTED_SSL_BACKEND_FOUND 0
-# endif /* HAVE_CURL_OPENSSL || HAVE_CURL_WOLFSSL || HAVE_CURL_GNUTLS || HAVE_CURL_NSS || HAVE_CURL_MBEDTLS */
+# endif /* HAVE_CURL_OPENSSL || HAVE_CURL_WOLFSSL || HAVE_CURL_GNUTLS || HAVE_CURL_NSS || HAVE_CURL_MBEDTLS || HAVE_CURL_SECTRANSP */
 #else
 # define COMPILE_SSL_LIB "none/other"
 # define COMPILE_SUPPORTED_SSL_BACKEND_FOUND 0
@@ -263,6 +266,19 @@ PYCURL_INTERNAL void pycurl_ssl_cleanup(
 #  define PYCURL_END_ALLOW_THREADS \
        Py_END_ALLOW_THREADS \
        self->state = NULL;
+#  define PYCURL_BEGIN_ALLOW_THREADS_EASY \
+       if (self->multi_stack == NULL) { \
+           self->state = PyThreadState_Get(); \
+           assert(self->state != NULL); \
+       } else { \
+           self->multi_stack->state = PyThreadState_Get(); \
+           assert(self->multi_stack->state != NULL); \
+       } \
+       Py_BEGIN_ALLOW_THREADS
+#  define PYCURL_END_ALLOW_THREADS_EASY \
+       PYCURL_END_ALLOW_THREADS \
+       if (self->multi_stack != NULL) \
+           self->multi_stack->state = NULL;
 #else
 #  define PYCURL_DECLARE_THREAD_STATE
 #  define PYCURL_ACQUIRE_THREAD() (1)
@@ -318,6 +334,10 @@ PyText_Check(PyObject *o);
 PYCURL_INTERNAL PyObject *
 PyText_FromString_Ignore(const char *string);
 
+/* Py_NewRef and Py_XNewRef - not part of Python's C API before 3.10 */
+static inline PyObject* my_Py_NewRef(PyObject *obj) { Py_INCREF(obj); return obj; }
+static inline PyObject* my_Py_XNewRef(PyObject *obj) { Py_XINCREF(obj); return obj; }
+
 struct CurlObject;
 
 PYCURL_INTERNAL void
@@ -371,16 +391,30 @@ create_and_set_error_object(struct CurlO
 #define PYCURL_MEMGROUP_POSTFIELDS      64
 /* CA certs object */
 #define PYCURL_MEMGROUP_CACERTS         128
+/* Curl slist objects */
+#define PYCURL_MEMGROUP_SLIST           256
 
 #define PYCURL_MEMGROUP_EASY \
     (PYCURL_MEMGROUP_CALLBACK | PYCURL_MEMGROUP_FILE | \
     PYCURL_MEMGROUP_HTTPPOST | PYCURL_MEMGROUP_POSTFIELDS | \
-    PYCURL_MEMGROUP_CACERTS)
+    PYCURL_MEMGROUP_CACERTS | PYCURL_MEMGROUP_SLIST)
 
 #define PYCURL_MEMGROUP_ALL \
     (PYCURL_MEMGROUP_ATTRDICT | PYCURL_MEMGROUP_EASY | \
     PYCURL_MEMGROUP_MULTI | PYCURL_MEMGROUP_SHARE)
 
+typedef struct CurlSlistObject {
+    PyObject_HEAD
+    struct curl_slist *slist;
+} CurlSlistObject;
+
+typedef struct CurlHttppostObject {
+    PyObject_HEAD
+    struct curl_httppost *httppost;
+    /* List of INC'ed references associated with httppost. */
+    PyObject *reflist;
+} CurlHttppostObject;
+
 typedef struct CurlObject {
     PyObject_HEAD
     PyObject *dict;                 /* Python attributes dictionary */
@@ -392,26 +426,24 @@ typedef struct CurlObject {
 #endif
     struct CurlMultiObject *multi_stack;
     struct CurlShareObject *share;
-    struct curl_httppost *httppost;
-    /* List of INC'ed references associated with httppost. */
-    PyObject *httppost_ref_list;
-    struct curl_slist *httpheader;
+    struct CurlHttppostObject *httppost;
+    struct CurlSlistObject *httpheader;
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
-    struct curl_slist *proxyheader;
+    struct CurlSlistObject *proxyheader;
 #endif
-    struct curl_slist *http200aliases;
-    struct curl_slist *quote;
-    struct curl_slist *postquote;
-    struct curl_slist *prequote;
-    struct curl_slist *telnetoptions;
+    struct CurlSlistObject *http200aliases;
+    struct CurlSlistObject *quote;
+    struct CurlSlistObject *postquote;
+    struct CurlSlistObject *prequote;
+    struct CurlSlistObject *telnetoptions;
 #ifdef HAVE_CURLOPT_RESOLVE
-    struct curl_slist *resolve;
+    struct CurlSlistObject *resolve;
 #endif
 #ifdef HAVE_CURL_7_20_0_OPTS
-    struct curl_slist *mail_rcpt;
+    struct CurlSlistObject *mail_rcpt;
 #endif
 #ifdef HAVE_CURLOPT_CONNECT_TO
-    struct curl_slist *connect_to;
+    struct CurlSlistObject *connect_to;
 #endif
     /* callbacks */
     PyObject *w_cb;
@@ -558,6 +590,11 @@ util_curl_xdecref(CurlObject *self, int
 PYCURL_INTERNAL PyObject *
 do_curl_setopt_filelike(CurlObject *self, int option, PyObject *obj);
 
+PYCURL_INTERNAL void
+util_curlslist_update(CurlSlistObject **old, struct curl_slist *slist);
+PYCURL_INTERNAL void
+util_curlhttppost_update(CurlObject *obj, struct curl_httppost *httppost, PyObject *reflist);
+
 PYCURL_INTERNAL PyObject *
 do_curl_getinfo_raw(CurlObject *self, PyObject *args);
 #if PY_MAJOR_VERSION >= 3
@@ -619,11 +656,15 @@ ssl_ctx_callback(CURL *curl, void *ssl_c
 #if !defined(PYCURL_SINGLE_FILE)
 /* Type objects */
 extern PyTypeObject Curl_Type;
+extern PyTypeObject CurlSlist_Type;
+extern PyTypeObject CurlHttppost_Type;
 extern PyTypeObject CurlMulti_Type;
 extern PyTypeObject CurlShare_Type;
 
 extern PyObject *ErrorObject;
 extern PyTypeObject *p_Curl_Type;
+extern PyTypeObject *p_CurlSlist_Type;
+extern PyTypeObject *p_CurlHttppost_Type;
 extern PyTypeObject *p_CurlMulti_Type;
 extern PyTypeObject *p_CurlShare_Type;
 extern PyObject *khkey_type;
@@ -647,9 +688,9 @@ extern PyMethodDef curlmultiobject_metho
 #endif /* !PYCURL_SINGLE_FILE */
 
 #if PY_MAJOR_VERSION >= 3
-# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC
+# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE
 #else
-# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS
+# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS | Py_TPFLAGS_BASETYPE
 #endif
 
 /* vi:ts=4:et:nowrap
diff -pruN 7.44.1-5/src/share.c 7.45.1-1/src/share.c
--- 7.44.1-5/src/share.c	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/share.c	2022-01-11 19:34:56.000000000 +0000
@@ -11,7 +11,7 @@ static void
 assert_share_state(const CurlShareObject *self)
 {
     assert(self != NULL);
-    assert(Py_TYPE(self) == p_CurlShare_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_CurlShare_Type) == 1);
 #ifdef WITH_THREAD
     assert(self->lock != NULL);
 #endif
@@ -38,7 +38,7 @@ do_share_new(PyTypeObject *subtype, PyOb
 #endif
     int *ptr;
     
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
+    if (subtype == p_CurlShare_Type && !PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
         return NULL;
     }
 
@@ -187,6 +187,9 @@ do_curlshare_setopt(CurlShareObject *sel
 #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 57, 0)
         case CURL_LOCK_DATA_CONNECT:
 #endif
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 61, 0)
+        case CURL_LOCK_DATA_PSL:
+#endif
             break;
         default:
             goto error;
diff -pruN 7.44.1-5/src/threadsupport.c 7.45.1-1/src/threadsupport.c
--- 7.44.1-5/src/threadsupport.c	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/src/threadsupport.c	2022-01-11 19:34:56.000000000 +0000
@@ -13,7 +13,7 @@ pycurl_get_thread_state(const CurlObject
      */
     if (self == NULL)
         return NULL;
-    assert(Py_TYPE(self) == p_Curl_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_Curl_Type) == 1);
     if (self->state != NULL)
     {
         /* inside perform() */
@@ -43,7 +43,7 @@ pycurl_get_thread_state_multi(const Curl
      */
     if (self == NULL)
         return NULL;
-    assert(Py_TYPE(self) == p_CurlMulti_Type);
+    assert(PyObject_IsInstance((PyObject *) self, (PyObject *) p_CurlMulti_Type) == 1);
     if (self->state != NULL)
     {
         /* inside multi_perform() */
diff -pruN 7.44.1-5/tests/app.py 7.45.1-1/tests/app.py
--- 7.44.1-5/tests/app.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/app.py	2022-01-11 19:34:56.000000000 +0000
@@ -30,6 +30,7 @@ def forbidden():
 def not_found():
     return bottle.HTTPResponse('not found', 404)
 
+@app.route('/postfields', method='get')
 @app.route('/postfields', method='post')
 def postfields():
     return json.dumps(dict(bottle.request.forms))
@@ -88,7 +89,7 @@ def header():
 # Thanks to bdarnell for the idea: https://github.com/pycurl/pycurl/issues/124
 @app.route('/header_utf8')
 def header_utf8():
-    header_value = bottle.request.headers[bottle.request.query['h']]
+    header_value = bottle.request.headers.get(bottle.request.query['h'], '' if py3 else b'')
     if py3:
         # header_value is a string, headers are decoded in latin1
         header_value = header_value.encode('latin1').decode('utf8')
diff -pruN 7.44.1-5/tests/duphandle_test.py 7.45.1-1/tests/duphandle_test.py
--- 7.44.1-5/tests/duphandle_test.py	1970-01-01 00:00:00.000000000 +0000
+++ 7.45.1-1/tests/duphandle_test.py	2022-01-11 19:34:56.000000000 +0000
@@ -0,0 +1,144 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:ts=4:et
+
+from . import localhost
+import pycurl
+import unittest
+import gc
+import weakref
+try:
+    import json
+except ImportError:
+    import simplejson as json
+
+from . import appmanager
+from . import util
+
+setup_module, teardown_module = appmanager.setup(('app', 8380))
+
+class DuphandleTest(unittest.TestCase):
+    def setUp(self):
+        self.orig = util.DefaultCurl()
+
+    def test_duphandle_attribute_dict(self):
+        self.orig.orig_attr = 'orig-value'
+        # attribute dict should be copied - the *object*, not the reference
+        dup = self.orig.duphandle()
+        assert dup.orig_attr == 'orig-value'
+        # cloned dict should be a separate object
+        dup.dup_attr = 'dup-value'
+        try:
+            self.orig.dup_attr == 'does not exist'
+        except AttributeError as error:
+            assert 'trying to obtain a non-existing attribute: dup_attr' in str(error.args)
+        else:
+            self.fail('should have raised AttributeError')
+        # dealloc self.orig - original dict is freed from memory
+        self.orig.close()
+        del self.orig
+        # cloned dict should still exist
+        assert dup.orig_attr == 'orig-value'
+        assert dup.dup_attr == 'dup-value'
+        dup.close()
+
+    def slist_check(self, handle, value, persistance=True):
+        body = util.BytesIO()
+        handle.setopt(pycurl.WRITEFUNCTION, body.write)
+        handle.setopt(pycurl.URL, 'http://%s:8380/header_utf8?h=x-test-header' % localhost)
+        handle.perform()
+        result = body.getvalue().decode('utf-8')
+        assert (result == value) == persistance
+
+    def slist_test(self, clear_func, *args):
+        # new slist object is created with ref count = 1
+        self.orig.setopt(pycurl.HTTPHEADER, ['x-test-header: orig-slist'])
+        # ref is copied and object incref'ed
+        dup1 = self.orig.duphandle()
+        # slist object is decref'ed and ref set to null
+        clear_func(*args)
+        # null ref is copied - no effect
+        dup2 = self.orig.duphandle()
+        # check slist object persistance
+        self.slist_check(dup1, 'orig-slist', True)
+        self.slist_check(dup2, 'orig-slist', False)
+        # check overwriting - orig slist is decref'ed to 0 and finally deallocated
+        # util_curlslist_update() and util_curlslist_dealloc()
+        dup1.setopt(pycurl.HTTPHEADER, ['x-test-header: dup-slist'])
+        self.slist_check(dup1, 'dup-slist', True)
+        # cleanup
+        dup1.close()
+        dup2.close()
+        self.orig.close()
+
+    def test_duphandle_slist_xdecref(self):
+        # util_curl_xdecref()
+        self.slist_test(self.orig.reset)
+
+    def test_duphandle_slist_unsetopt(self):
+        # util_curl_unsetopt()
+        self.slist_test(self.orig.unsetopt, pycurl.HTTPHEADER)
+
+    def httppost_check(self, handle, value, persistance=True):
+        body = util.BytesIO()
+        handle.setopt(pycurl.WRITEFUNCTION, body.write)
+        handle.setopt(pycurl.URL, 'http://%s:8380/postfields' % localhost)
+        handle.perform()
+        result = json.loads(body.getvalue())
+        assert (result == value) == persistance
+
+    def httppost_test(self, clear_func, *args):
+        self.orig.setopt(pycurl.HTTPPOST, [
+            ('field', (pycurl.FORM_CONTENTS, 'orig-httppost')),
+        ])
+        dup1 = self.orig.duphandle()
+        clear_func(*args)
+        dup2 = self.orig.duphandle()
+        self.httppost_check(dup1, {'field': 'orig-httppost'}, True)
+        self.httppost_check(dup2, {'field': 'orig-httppost'}, False)
+        # util_curlhttppost_update() and util_curlhttppost_dealloc()
+        dup1.setopt(pycurl.HTTPPOST, [
+            ('field', (pycurl.FORM_CONTENTS, 'dup-httppost')),
+        ])
+        self.httppost_check(dup1, {'field': 'dup-httppost'}, True)
+        dup1.close()
+        dup2.close()
+        self.orig.close()
+
+    def test_duphandle_httppost_xdecref(self):
+        # util_curl_xdecref()
+        self.httppost_test(self.orig.reset)
+
+    def test_duphandle_httppost_unsetopt(self):
+        # util_curl_unsetopt()
+        self.httppost_test(self.orig.unsetopt, pycurl.HTTPPOST)
+
+    def test_duphandle_references(self):
+        body = util.BytesIO()
+        def callback(data):
+            body.write(data)
+        callback_ref = weakref.ref(callback)
+        # preliminary checks of gc and weakref working as expected
+        assert gc.get_referrers(callback) == []
+        assert callback_ref() is not None
+        # setopt - callback ref is copied and callback incref'ed
+        self.orig.setopt(pycurl.WRITEFUNCTION, callback)
+        assert gc.get_referrers(callback) == [self.orig]
+        # duphandle - callback ref is copied and callback incref'ed
+        dup = self.orig.duphandle()
+        assert set(gc.get_referrers(callback)) == {self.orig, dup}
+        # dealloc self.orig and decref callback
+        self.orig.close()
+        del self.orig
+        assert gc.get_referrers(callback) == [dup]
+        # decref callback again - back to ref count = 1
+        del callback
+        assert callback_ref() is not None
+        # check that callback object still exists and is invoked
+        dup.setopt(pycurl.URL, 'http://%s:8380/success' % localhost)
+        dup.perform()
+        result = body.getvalue().decode('utf-8')
+        assert result == 'success'
+        # final decref - callback is deallocated
+        dup.close()
+        assert callback_ref() is None
diff -pruN 7.44.1-5/tests/fake-curl/libcurl/Makefile 7.45.1-1/tests/fake-curl/libcurl/Makefile
--- 7.44.1-5/tests/fake-curl/libcurl/Makefile	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/fake-curl/libcurl/Makefile	2022-01-11 19:23:49.000000000 +0000
@@ -13,10 +13,16 @@ clean:
 
 CC = `curl-config --cc`
 CFLAGS += `curl-config --cflags`
+UNAME := $(shell uname -s)
+ifeq ($(UNAME),Darwin)
+	SONAME_FLAG = -install_name
+else
+	SONAME_FLAG = -soname
+endif
 
 .c.so:
 	$(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) -shared -fPIC \
-		-Wl,-soname,$@ -o $@ $<
+		-Wl,$(SONAME_FLAG),$@ -o $@ $<
 
 show-targets:
 	ls *c |sed -e 's/.c$$/.so/' | awk '{print $$1 " \\"}'
diff -pruN 7.44.1-5/tests/memory_mgmt_test.py 7.45.1-1/tests/memory_mgmt_test.py
--- 7.44.1-5/tests/memory_mgmt_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/memory_mgmt_test.py	2021-12-27 23:13:33.000000000 +0000
@@ -297,7 +297,7 @@ class MemoryMgmtTest(unittest.TestCase):
 
         gc.collect()
         after_object_count = len(gc.get_objects())
-        self.assert_(after_object_count <= before_object_count + 1000, 'Grew from %d to %d objects' % (before_object_count, after_object_count))
+        self.assertTrue(after_object_count <= before_object_count + 1000, 'Grew from %d to %d objects' % (before_object_count, after_object_count))
         c.close()
 
     def test_form_bufferptr_memory_leak_gh267(self):
@@ -317,7 +317,7 @@ class MemoryMgmtTest(unittest.TestCase):
 
         gc.collect()
         after_object_count = len(gc.get_objects())
-        self.assert_(after_object_count <= before_object_count + 1000, 'Grew from %d to %d objects' % (before_object_count, after_object_count))
+        self.assertTrue(after_object_count <= before_object_count + 1000, 'Grew from %d to %d objects' % (before_object_count, after_object_count))
         c.close()
 
     def do_data_refcounting(self, option):
diff -pruN 7.44.1-5/tests/multi_callback_test.py 7.45.1-1/tests/multi_callback_test.py
--- 7.44.1-5/tests/multi_callback_test.py	1970-01-01 00:00:00.000000000 +0000
+++ 7.45.1-1/tests/multi_callback_test.py	2022-03-13 07:10:38.000000000 +0000
@@ -0,0 +1,100 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:ts=4:et
+
+from . import localhost
+import pycurl
+import pytest
+import sys
+import unittest
+
+from . import appmanager
+from . import util
+
+setup_module, teardown_module = appmanager.setup(('app', 8380))
+
+class MultiCallbackTest(unittest.TestCase):
+    def setUp(self):
+        self.easy = util.DefaultCurl()
+        self.easy.setopt(pycurl.URL, 'http://%s:8380/long_pause' % localhost)
+        self.multi = pycurl.CurlMulti()
+        self.multi.setopt(pycurl.M_SOCKETFUNCTION, self.socket_callback)
+        self.multi.setopt(pycurl.M_TIMERFUNCTION, self.timer_callback)
+        self.socket_result = None
+        self.timer_result = None
+        self.sockets = {}
+
+    def tearDown(self):
+        self.multi.close()
+        self.easy.close()
+
+    def socket_callback(self, ev_bitmask, sock_fd, multi, data):
+        self.socket_result = (sock_fd, ev_bitmask)
+        if ev_bitmask & pycurl.POLL_REMOVE:
+            self.sockets.pop(sock_fd)
+        else:
+            self.sockets[sock_fd] = ev_bitmask | self.sockets.get(sock_fd, 0)
+
+    def timer_callback(self, timeout_ms):
+        self.timer_result = timeout_ms
+
+    def partial_transfer(self):
+        perform = True
+        def write_callback(data):
+            nonlocal perform
+            perform = False
+        self.easy.setopt(pycurl.WRITEFUNCTION, write_callback)
+        self.multi.add_handle(self.easy)
+        self.multi.socket_action(pycurl.SOCKET_TIMEOUT, 0)
+        while self.sockets and perform:
+            for socket, action in tuple(self.sockets.items()):
+                self.multi.socket_action(socket, action)
+
+    # multi.socket_action must call both SOCKETFUNCTION and TIMERFUNCTION at
+    # various points during the transfer (at least at the start and end)
+    @pytest.mark.xfail(sys.platform == 'darwin', reason='https://github.com/pycurl/pycurl/issues/729')
+    def test_multi_socket_action(self):
+        self.multi.add_handle(self.easy)
+        self.timer_result = None
+        self.socket_result = None
+        self.multi.socket_action(pycurl.SOCKET_TIMEOUT, 0)
+        assert self.socket_result is not None
+        assert self.timer_result is not None
+
+    # multi.add_handle must call TIMERFUNCTION to schedule a kick-start
+    def test_multi_add_handle(self):
+        self.multi.add_handle(self.easy)
+        assert self.timer_result is not None
+
+    # (mid-transfer) multi.remove_handle must call SOCKETFUNCTION to remove sockets
+    @pytest.mark.xfail(sys.platform == 'darwin', reason='https://github.com/pycurl/pycurl/issues/729')
+    def test_multi_remove_handle(self):
+        self.multi.add_handle(self.easy)
+        self.multi.socket_action(pycurl.SOCKET_TIMEOUT, 0)
+        self.socket_result = None
+        self.multi.remove_handle(self.easy)
+        assert self.socket_result is not None
+
+    # (mid-transfer) easy.pause(PAUSE_ALL) must call SOCKETFUNCTION to remove sockets
+    # (mid-transfer) easy.pause(PAUSE_CONT) must call TIMERFUNCTION to resume
+    @pytest.mark.xfail(sys.platform == 'darwin', reason='https://github.com/pycurl/pycurl/issues/729')
+    def test_easy_pause_unpause(self):
+        self.partial_transfer()
+        self.socket_result = None
+        # libcurl will now inform us that we should remove some sockets
+        self.easy.pause(pycurl.PAUSE_ALL)
+        assert self.socket_result is not None
+        self.socket_result = None
+        self.timer_result = None
+        # libcurl will now tell us to add those sockets and schedule a kickstart
+        self.easy.pause(pycurl.PAUSE_CONT)
+        assert self.socket_result is not None
+        assert self.timer_result is not None
+
+    # (mid-transfer) easy.close() must call SOCKETFUNCTION to remove sockets
+    @pytest.mark.xfail(sys.platform == 'darwin', reason='https://github.com/pycurl/pycurl/issues/729')
+    def test_easy_close(self):
+        self.partial_transfer()
+        self.socket_result = None
+        self.easy.close()
+        assert self.socket_result is not None
diff -pruN 7.44.1-5/tests/multi_option_constants_test.py 7.45.1-1/tests/multi_option_constants_test.py
--- 7.44.1-5/tests/multi_option_constants_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/multi_option_constants_test.py	2022-01-11 19:34:56.000000000 +0000
@@ -63,6 +63,7 @@ class MultiOptionConstantsTest(unittest.
         input = (util.u('test1'), util.u('test2'))
         self.m.setopt(option, input)
         self.m.setopt(option, ())
+        self.m.setopt(option, None)
 
         try:
             self.m.setopt(option, 1)
@@ -70,3 +71,19 @@ class MultiOptionConstantsTest(unittest.
         except TypeError:
             exc = sys.exc_info()[1]
             assert 'integers are not supported for this option' in str(exc)
+
+    def test_multi_callback_opts(self):
+        def callback(*args, **kwargs):
+            pass
+        self.m.setopt(pycurl.M_SOCKETFUNCTION, callback)
+        self.m.setopt(pycurl.M_TIMERFUNCTION, callback)
+        self.m.setopt(pycurl.M_SOCKETFUNCTION, None)
+        self.m.setopt(pycurl.M_TIMERFUNCTION, None)
+
+    def test_multi_unsetopt_unsupported(self):
+        try:
+            self.m.setopt(pycurl.M_MAXCONNECTS, None)
+            self.fail('expected to raise')
+        except TypeError:
+            exc = sys.exc_info()[1]
+            assert 'unsetting is not supported for this option' in str(exc)
diff -pruN 7.44.1-5/tests/option_constants_test.py 7.45.1-1/tests/option_constants_test.py
--- 7.44.1-5/tests/option_constants_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/option_constants_test.py	2022-01-11 19:23:49.000000000 +0000
@@ -241,7 +241,7 @@ class OptionConstantsTest(unittest.TestC
         curl.close()
 
     @util.min_libcurl(7, 42, 0)
-    @util.only_ssl_backends('nss')
+    @util.only_ssl_backends('nss', 'secure-transport')
     def test_ssl_falsestart(self):
         curl = pycurl.Curl()
         curl.setopt(curl.SSL_FALSESTART, 1)
@@ -263,7 +263,7 @@ class OptionConstantsTest(unittest.TestC
         curl.setopt(curl.ISSUERCERT, '/bogus-issuercert')
         curl.close()
 
-    @util.only_ssl
+    @util.only_ssl_backends('openssl', 'gnutls', 'nss')
     def test_capath(self):
         curl = pycurl.Curl()
         curl.setopt(curl.CAPATH, '/bogus-capath')
@@ -271,7 +271,7 @@ class OptionConstantsTest(unittest.TestC
 
     # CURLOPT_PROXY_CAPATH was introduced in libcurl-7.52.0
     @util.min_libcurl(7, 52, 0)
-    @util.only_ssl
+    @util.only_ssl_backends('openssl', 'gnutls', 'nss')
     def test_proxy_capath(self):
         curl = pycurl.Curl()
         curl.setopt(curl.PROXY_CAPATH, '/bogus-capath')
@@ -331,7 +331,7 @@ class OptionConstantsTest(unittest.TestC
         curl.setopt(curl.RANDOM_FILE, '/bogus-random')
         curl.close()
 
-    @util.only_ssl_backends('openssl', 'gnutls')
+    @util.only_ssl_backends('openssl', 'gnutls', 'secure-transport')
     def test_egdsocket(self):
         curl = pycurl.Curl()
         curl.setopt(curl.EGDSOCKET, '/bogus-egdsocket')
diff -pruN 7.44.1-5/tests/post_test.py 7.45.1-1/tests/post_test.py
--- 7.44.1-5/tests/post_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/post_test.py	2022-03-09 23:12:32.000000000 +0000
@@ -86,7 +86,7 @@ class PostTest(unittest.TestCase):
 
     def test_post_file(self):
         path = os.path.join(os.path.dirname(__file__), '..', 'README.rst')
-        f = open(path)
+        f = open(path, newline='')
         try:
             contents = f.read()
         finally:
diff -pruN 7.44.1-5/tests/reload_test.py 7.45.1-1/tests/reload_test.py
--- 7.44.1-5/tests/reload_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/reload_test.py	2021-12-27 23:13:33.000000000 +0000
@@ -14,6 +14,6 @@ class ReloadTest(unittest.TestCase):
             reload_fn = reload
         except NameError:
             # python 3
-            import imp
-            reload_fn = imp.reload
+            import importlib
+            reload_fn = importlib.reload
         reload_fn(pycurl)
diff -pruN 7.44.1-5/tests/setopt_lifecycle_test.py 7.45.1-1/tests/setopt_lifecycle_test.py
--- 7.44.1-5/tests/setopt_lifecycle_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/setopt_lifecycle_test.py	2021-12-27 23:13:33.000000000 +0000
@@ -17,6 +17,7 @@ from . import util
 setup_module, teardown_module = appmanager.setup(('app', 8380))
 
 class TestString(str):
+    __test__ = False
     def __del__(self):
         self.replace('1', '2')
         #print self
diff -pruN 7.44.1-5/tests/setopt_test.py 7.45.1-1/tests/setopt_test.py
--- 7.44.1-5/tests/setopt_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/setopt_test.py	2021-12-27 23:13:33.000000000 +0000
@@ -58,13 +58,13 @@ class SetoptTest(unittest.TestCase):
         io = util.BytesIO()
         self.curl.setopt(self.curl.WRITEDATA, io)
         self.curl.perform()
-        self.assertEquals(util.b('foo'), io.getvalue())
+        self.assertEqual(util.b('foo'), io.getvalue())
 
         self.curl.unsetopt(self.curl.HTTPHEADER)
         io = util.BytesIO()
         self.curl.setopt(self.curl.WRITEDATA, io)
         self.curl.perform()
-        self.assertEquals(util.b(''), io.getvalue())
+        self.assertEqual(util.b(''), io.getvalue())
 
     def test_set_httpheader_none(self):
         self.curl.setopt(self.curl.HTTPHEADER, ('x-test: foo',))
@@ -72,13 +72,13 @@ class SetoptTest(unittest.TestCase):
         io = util.BytesIO()
         self.curl.setopt(self.curl.WRITEDATA, io)
         self.curl.perform()
-        self.assertEquals(util.b('foo'), io.getvalue())
+        self.assertEqual(util.b('foo'), io.getvalue())
 
         self.curl.setopt(self.curl.HTTPHEADER, None)
         io = util.BytesIO()
         self.curl.setopt(self.curl.WRITEDATA, io)
         self.curl.perform()
-        self.assertEquals(util.b(''), io.getvalue())
+        self.assertEqual(util.b(''), io.getvalue())
 
     @util.min_libcurl(7, 37, 0)
     def test_proxyheader_list(self):
diff -pruN 7.44.1-5/tests/subclass_test.py 7.45.1-1/tests/subclass_test.py
--- 7.44.1-5/tests/subclass_test.py	1970-01-01 00:00:00.000000000 +0000
+++ 7.45.1-1/tests/subclass_test.py	2022-01-11 19:34:56.000000000 +0000
@@ -0,0 +1,88 @@
+#! /usr/bin/env python
+# -*- coding: utf-8 -*-
+# vi:ts=4:et
+
+try:
+    import unittest2 as unittest
+except ImportError:
+    import unittest
+import pycurl
+
+CLASSES = (pycurl.Curl, pycurl.CurlMulti, pycurl.CurlShare)
+
+class SubclassTest(unittest.TestCase):
+    def test_baseclass_init(self):
+        # base classes do not accept any arguments on initialization
+        for baseclass in CLASSES:
+            try:
+                baseclass(0)
+            except TypeError:
+                pass
+            else:
+                raise AssertionError('Base class accepted invalid args')
+            try:
+                baseclass(a=1)
+            except TypeError:
+                pass
+            else:
+                raise AssertionError('Base class accepted invalid kwargs')
+
+    def test_subclass_create(self):
+        for baseclass in CLASSES:
+            # test creation of a subclass
+            class MyCurlClass(baseclass):
+                pass
+            # test creation of its object
+            obj = MyCurlClass()
+            # must be of type subclass, but also an instance of base class
+            assert type(obj) == MyCurlClass
+            assert isinstance(obj, baseclass)
+
+    def test_subclass_init(self):
+        for baseclass in CLASSES:
+            class MyCurlClass(baseclass):
+                def __init__(self, x, y=4):
+                    self.x = x
+                    self.y = y
+            # subclass __init__ must be able to accept args and kwargs
+            obj = MyCurlClass(3)
+            assert obj.x == 3
+            assert obj.y == 4
+            obj = MyCurlClass(5, y=6)
+            assert obj.x == 5
+            assert obj.y == 6
+            # and it must throw TypeError if arguments don't match
+            try:
+                MyCurlClass(1, 2, 3, kwarg=4)
+            except TypeError:
+                pass
+            else:
+                raise AssertionError('Subclass accepted invalid arguments')
+
+    def test_subclass_method(self):
+        for baseclass in CLASSES:
+            class MyCurlClass(baseclass):
+                def my_method(self, x):
+                    return x + 1
+            obj = MyCurlClass()
+            # methods must be able to accept arguments and return a value
+            assert obj.my_method(1) == 2
+
+    def test_subclass_method_override(self):
+        # setopt args for each base class
+        args = {
+            pycurl.Curl:      (pycurl.VERBOSE, 1),
+            pycurl.CurlMulti: (pycurl.M_MAXCONNECTS, 3),
+            pycurl.CurlShare: (pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE),
+        }
+        for baseclass in CLASSES:
+            class MyCurlClass(baseclass):
+                def setopt(self, option, value):
+                    # base method must not be overwritten
+                    assert super().setopt != self.setopt
+                    # base method mut be callable, setopt must return None
+                    assert super().setopt(option, value) is None
+                    # return something else
+                    return 'my setopt'
+            obj = MyCurlClass()
+            assert obj.setopt(*args[baseclass]) == 'my setopt'
diff -pruN 7.44.1-5/tests/unset_range_test.py 7.45.1-1/tests/unset_range_test.py
--- 7.44.1-5/tests/unset_range_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/unset_range_test.py	2022-03-09 23:12:32.000000000 +0000
@@ -5,6 +5,7 @@
 import os.path
 import pycurl
 import unittest
+import urllib.request
 
 class UnsetRangeTest(unittest.TestCase):
     def setUp(self):
@@ -20,7 +21,8 @@ class UnsetRangeTest(unittest.TestCase):
 
         # download bytes 0-9 of the script itself through the file:// protocol
         self.read = 0
-        self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(__file__).replace('\\', '/'))
+        url = 'file:' + urllib.request.pathname2url(os.path.abspath(__file__))
+        self.curl.setopt(pycurl.URL, url)
         self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
         self.curl.setopt(pycurl.RANGE, '0-9')
         self.curl.perform()
diff -pruN 7.44.1-5/tests/util.py 7.45.1-1/tests/util.py
--- 7.44.1-5/tests/util.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/util.py	2022-01-11 19:23:49.000000000 +0000
@@ -175,6 +175,8 @@ def only_ssl_backends(*backends):
                 current_backend = 'gnutls'
             elif 'NSS/' in pycurl.version:
                 current_backend = 'nss'
+            elif 'SecureTransport' in pycurl.version:
+                current_backend = 'secure-transport'
             else:
                 current_backend = 'none'
             if current_backend not in backends:
diff -pruN 7.44.1-5/tests/write_abort_test.py 7.45.1-1/tests/write_abort_test.py
--- 7.44.1-5/tests/write_abort_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/write_abort_test.py	2022-03-09 23:12:32.000000000 +0000
@@ -6,6 +6,7 @@ import os.path
 import pycurl
 import sys
 import unittest
+import urllib.request
 
 class WriteAbortTest(unittest.TestCase):
     def setUp(self):
@@ -27,7 +28,8 @@ class WriteAbortTest(unittest.TestCase):
             pass
 
         # download the script itself through the file:// protocol into write_cb
-        self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(__file__).replace('\\', '/'))
+        url = 'file:' + urllib.request.pathname2url(os.path.abspath(__file__))
+        self.curl.setopt(pycurl.URL, url)
         self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
         try:
             self.curl.perform()
diff -pruN 7.44.1-5/tests/write_cb_bogus_test.py 7.45.1-1/tests/write_cb_bogus_test.py
--- 7.44.1-5/tests/write_cb_bogus_test.py	2021-08-09 01:47:03.000000000 +0000
+++ 7.45.1-1/tests/write_cb_bogus_test.py	2022-03-09 23:12:32.000000000 +0000
@@ -6,6 +6,7 @@ import os.path
 import pycurl
 import sys
 import unittest
+import urllib.request
 
 class WriteAbortTest(unittest.TestCase):
     def setUp(self):
@@ -28,7 +29,8 @@ class WriteAbortTest(unittest.TestCase):
 
     def check(self, write_cb):
         # download the script itself through the file:// protocol into write_cb
-        self.curl.setopt(pycurl.URL, 'file://' + os.path.abspath(__file__).replace('\\', '/'))
+        url = 'file:' + urllib.request.pathname2url(os.path.abspath(__file__))
+        self.curl.setopt(pycurl.URL, url)
         self.curl.setopt(pycurl.WRITEFUNCTION, write_cb)
         try:
             self.curl.perform()
diff -pruN 7.44.1-5/winbuild.py 7.45.1-1/winbuild.py
--- 7.44.1-5/winbuild.py	2021-08-15 19:30:54.000000000 +0000
+++ 7.45.1-1/winbuild.py	2022-03-13 07:12:42.000000000 +0000
@@ -103,7 +103,7 @@ class Config:
     # whether to build binary wheels
     build_wheels = True
     # pycurl version to build, we should know this ourselves
-    pycurl_version = '7.44.1'
+    pycurl_version = '7.45.1'
 
     # Sometimes vc14 does not include windows sdk path in vcvars which breaks stuff.
     # another application for this is to supply normaliz.lib for vc9
