pycurl-7.43.0.2/ 0000755 0001750 0001750 00000000000 13304422066 012307 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/setup.py 0000644 0001750 0001750 00000105375 13304422026 014030 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
"""Setup script for the PycURL module distribution."""
PACKAGE = "pycurl"
PY_PACKAGE = "curl"
VERSION = "7.43.0.2"
import glob, os, re, sys, subprocess
import distutils
try:
import wheel
if wheel:
from setuptools import setup
except ImportError:
from distutils.core import setup
from distutils.extension import Extension
from distutils.util import split_quoted
from distutils.version import LooseVersion
py3 = sys.version_info[0] == 3
try:
# python 2
exception_base = StandardError
except NameError:
# python 3
exception_base = Exception
class ConfigurationError(exception_base):
pass
def fail(msg):
sys.stderr.write(msg + "\n")
exit(10)
def scan_argv(argv, s, default=None):
p = default
i = 1
while i < len(argv):
arg = argv[i]
if str.find(arg, s) == 0:
if s.endswith('='):
# --option=value
p = arg[len(s):]
if s != '--openssl-lib-name=':
assert p, arg
else:
# --option
# set value to True
p = True
del argv[i]
else:
i = i + 1
##print argv
return p
def scan_argvs(argv, s):
p = []
i = 1
while i < len(argv):
arg = argv[i]
if str.find(arg, s) == 0:
if s.endswith('='):
# --option=value
p.append(arg[len(s):])
if s != '--openssl-lib-name=':
assert p[-1], arg
else:
# --option
# set value to True
raise Exception('specification must end with =')
del argv[i]
else:
i = i + 1
##print argv
return p
class ExtensionConfiguration(object):
def __init__(self, argv=[]):
# we mutate argv, this is necessary because
# setuptools does not recognize pycurl-specific options
self.argv = argv
self.original_argv = argv[:]
self.include_dirs = []
self.define_macros = [("PYCURL_VERSION", '"%s"' % VERSION)]
self.library_dirs = []
self.libraries = []
self.runtime_library_dirs = []
self.extra_objects = []
self.extra_compile_args = []
self.extra_link_args = []
self.configure()
@property
def define_symbols(self):
return [symbol for symbol, expansion in self.define_macros]
# append contents of an environment variable to library_dirs[]
def add_libdirs(self, envvar, sep, fatal=False):
v = os.environ.get(envvar)
if not v:
return
for dir in str.split(v, sep):
dir = str.strip(dir)
if not dir:
continue
dir = os.path.normpath(dir)
if os.path.isdir(dir):
if not dir in self.library_dirs:
self.library_dirs.append(dir)
elif fatal:
fail("FATAL: bad directory %s in environment variable %s" % (dir, envvar))
def detect_features(self):
p = subprocess.Popen((self.curl_config(), '--features'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "Problem running `%s' --features" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
curl_has_ssl = False
for feature in split_quoted(stdout.decode()):
if feature == 'SSL':
# this means any ssl library, not just openssl.
# we set the ssl flag to check for ssl library mismatch
# at link time and run time
self.define_macros.append(('HAVE_CURL_SSL', 1))
curl_has_ssl = True
self.curl_has_ssl = curl_has_ssl
def ssl_options(self):
return {
'--with-openssl': self.using_openssl,
'--with-ssl': self.using_openssl,
'--with-gnutls': self.using_gnutls,
'--with-nss': self.using_nss,
}
def detect_ssl_option(self):
for option in self.ssl_options():
if scan_argv(self.argv, option) is not None:
for other_option in self.ssl_options():
if option != other_option:
if scan_argv(self.argv, other_option) is not None:
raise ConfigurationError('Cannot give both %s and %s' % (option, other_option))
return option
def detect_ssl_backend(self):
ssl_lib_detected = False
if 'PYCURL_SSL_LIBRARY' in os.environ:
ssl_lib = os.environ['PYCURL_SSL_LIBRARY']
if ssl_lib in ['openssl', 'gnutls', 'nss']:
ssl_lib_detected = True
getattr(self, 'using_%s' % ssl_lib)()
else:
raise ConfigurationError('Invalid value "%s" for PYCURL_SSL_LIBRARY' % ssl_lib)
option = self.detect_ssl_option()
if option:
ssl_lib_detected = True
self.ssl_options()[option]()
# ssl detection - ssl libraries are added
if not ssl_lib_detected:
libcurl_dll_path = scan_argv(self.argv, "--libcurl-dll=")
if libcurl_dll_path is not None:
if self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path):
ssl_lib_detected = True
if not ssl_lib_detected:
# self.sslhintbuf is a hack
for arg in split_quoted(self.sslhintbuf):
if arg[:2] == "-l":
if arg[2:] == 'ssl':
self.using_openssl()
ssl_lib_detected = True
break
if arg[2:] == 'gnutls':
self.using_gnutls()
ssl_lib_detected = True
break
if arg[2:] == 'ssl3':
self.using_nss()
ssl_lib_detected = True
break
if not ssl_lib_detected and len(self.argv) == len(self.original_argv) \
and not os.environ.get('PYCURL_CURL_CONFIG') \
and not os.environ.get('PYCURL_SSL_LIBRARY'):
# this path should only be taken when no options or
# configuration environment variables are given to setup.py
ssl_lib_detected = self.detect_ssl_lib_on_centos6()
self.ssl_lib_detected = ssl_lib_detected
def curl_config(self):
try:
return self._curl_config
except AttributeError:
curl_config = os.environ.get('PYCURL_CURL_CONFIG', "curl-config")
curl_config = scan_argv(self.argv, "--curl-config=", curl_config)
self._curl_config = curl_config
return curl_config
def configure_unix(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"))
try:
p = subprocess.Popen((self.curl_config(), '--version'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except OSError:
exc = sys.exc_info()[1]
msg = 'Could not run curl-config: %s' % str(exc)
raise ConfigurationError(msg)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "`%s' not found -- please install the libcurl development files or specify --curl-config=/path/to/curl-config" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
libcurl_version = stdout.decode().strip()
print("Using %s (%s)" % (self.curl_config(), libcurl_version))
p = subprocess.Popen((self.curl_config(), '--cflags'),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() != 0:
msg = "Problem running `%s' --cflags" % self.curl_config()
if stderr:
msg += ":\n" + stderr.decode()
raise ConfigurationError(msg)
for arg in split_quoted(stdout.decode()):
if arg[:2] == "-I":
# do not add /usr/include
if not re.search(r"^\/+usr\/+include\/*$", arg[2:]):
self.include_dirs.append(arg[2:])
else:
self.extra_compile_args.append(arg)
# Obtain linker flags/libraries to link against.
# In theory, all we should need is `curl-config --libs`.
# Apparently on some platforms --libs fails and --static-libs works,
# so try that.
# If --libs succeeds do not try --static-libs; see
# https://github.com/pycurl/pycurl/issues/52 for more details.
# If neither --libs nor --static-libs work, fail.
#
# --libs/--static-libs are also used for SSL detection.
# libcurl may be configured such that --libs only includes -lcurl
# without any of libcurl's dependent libraries, but the dependent
# libraries would be included in --static-libs (unless libcurl
# was built with static libraries disabled).
# Therefore we largely ignore (see below) --static-libs output for
# libraries and flags if --libs succeeded, but consult both outputs
# for hints as to which SSL library libcurl is linked against.
# More information: https://github.com/pycurl/pycurl/pull/147
#
# The final point is we should link agaist the SSL library in use
# even if libcurl does not tell us to, because *we* invoke functions
# in that SSL library. This means any SSL libraries found in
# --static-libs are forwarded to our libraries.
optbuf = ''
sslhintbuf = ''
errtext = ''
for option in ["--libs", "--static-libs"]:
p = subprocess.Popen((self.curl_config(), option),
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.wait() == 0:
if optbuf == '':
# first successful call
optbuf = stdout.decode()
# optbuf only has output from this call
sslhintbuf += optbuf
else:
# second successful call
sslhintbuf += stdout.decode()
else:
if optbuf == '':
# no successful call yet
errtext += stderr.decode()
else:
# first call succeeded and second call failed
# ignore stderr and the error exit
pass
if optbuf == "":
msg = "Neither curl-config --libs nor curl-config --static-libs" +\
" succeeded and produced output"
if errtext:
msg += ":\n" + errtext
raise ConfigurationError(msg)
# hack
self.sslhintbuf = sslhintbuf
self.detect_features()
if self.curl_has_ssl:
self.detect_ssl_backend()
if not self.ssl_lib_detected:
raise ConfigurationError('''\
Curl is configured to use SSL, but we have not been able to determine \
which SSL backend it is using. Please see PycURL documentation for how to \
specify the SSL backend manually.''')
else:
if self.detect_ssl_option():
sys.stderr.write("Warning: SSL backend specified manually but libcurl does not use SSL\n")
# libraries and options - all libraries and options are forwarded
# but if --libs succeeded, --static-libs output is ignored
for arg in split_quoted(optbuf):
if arg[:2] == "-l":
self.libraries.append(arg[2:])
elif arg[:2] == "-L":
self.library_dirs.append(arg[2:])
else:
self.extra_link_args.append(arg)
if not self.libraries:
self.libraries.append("curl")
# Add extra compile flag for MacOS X
if sys.platform[:-1] == "darwin":
self.extra_link_args.append("-flat_namespace")
# Recognize --avoid-stdio on Unix so that it can be tested
self.check_avoid_stdio()
def detect_ssl_lib_from_libcurl_dll(self, libcurl_dll_path):
ssl_lib_detected = False
curl_version_info = self.get_curl_version_info(libcurl_dll_path)
ssl_version = curl_version_info.ssl_version
if py3:
# ssl_version is bytes on python 3
ssl_version = ssl_version.decode('ascii')
if ssl_version.startswith('OpenSSL/') or ssl_version.startswith('LibreSSL/'):
self.using_openssl()
ssl_lib_detected = True
elif ssl_version.startswith('GnuTLS/'):
self.using_gnutls()
ssl_lib_detected = True
elif ssl_version.startswith('NSS/'):
self.using_nss()
ssl_lib_detected = True
return ssl_lib_detected
def detect_ssl_lib_on_centos6(self):
import platform
from ctypes.util import find_library
os_name = platform.system()
if os_name != 'Linux':
return False
dist_name, dist_version, _ = platform.dist()
dist_version = dist_version.split('.')[0]
if dist_name != 'centos' or dist_version != '6':
return False
libcurl_dll_path = find_library('curl')
return self.detect_ssl_lib_from_libcurl_dll(libcurl_dll_path)
def configure_windows(self):
# Windows users have to pass --curl-dir parameter to specify path
# to libcurl, because there is no curl-config on windows at all.
curl_dir = scan_argv(self.argv, "--curl-dir=")
if curl_dir is None:
fail("Please specify --curl-dir=/path/to/built/libcurl")
if not os.path.exists(curl_dir):
fail("Curl directory does not exist: %s" % curl_dir)
if not os.path.isdir(curl_dir):
fail("Curl directory is not a directory: %s" % curl_dir)
print("Using curl directory: %s" % curl_dir)
self.include_dirs.append(os.path.join(curl_dir, "include"))
# libcurl windows documentation states that for linking against libcurl
# dll, the import library name is libcurl_imp.lib.
# For libcurl 7.46.0, the library name is libcurl.lib.
# And static library name is libcurl_a.lib by default as of libcurl 7.46.0.
# override with: --libcurl-lib-name=libcurl_imp.lib
curl_lib_name = scan_argv(self.argv, '--libcurl-lib-name=', 'libcurl.lib')
# openssl 1.1.0 changed its library names
# from libeay32.lib/ssleay32.lib to libcrypto.lib/libssl.lib.
# at the same time they dropped thread locking callback interface,
# meaning the correct usage of this option is --openssl-lib-name=""
self.openssl_lib_name = scan_argv(self.argv, '--openssl-lib-name=', 'libeay32.lib')
for lib in scan_argvs(self.argv, '--link-arg='):
self.extra_link_args.append(lib)
if scan_argv(self.argv, "--use-libcurl-dll") is not None:
libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
self.extra_link_args.extend(["ws2_32.lib"])
if str.find(sys.version, "MSC") >= 0:
# build a dll
self.extra_compile_args.append("-MD")
else:
self.extra_compile_args.append("-DCURL_STATICLIB")
libcurl_lib_path = os.path.join(curl_dir, "lib", curl_lib_name)
self.extra_link_args.extend(["gdi32.lib", "wldap32.lib", "winmm.lib", "ws2_32.lib",])
if not os.path.exists(libcurl_lib_path):
fail("libcurl.lib does not exist at %s.\nCurl directory must point to compiled libcurl (bin/include/lib subdirectories): %s" %(libcurl_lib_path, curl_dir))
self.extra_objects.append(libcurl_lib_path)
if scan_argv(self.argv, '--with-openssl') is not None or scan_argv(self.argv, '--with-ssl') is not None:
self.using_openssl()
self.check_avoid_stdio()
# make pycurl binary work on windows xp.
# we use inet_ntop which was added in vista and implement a fallback.
# our implementation will not be compiled with _WIN32_WINNT targeting
# vista or above, thus said binary won't work on xp.
# https://curl.haxx.se/mail/curlpython-2013-12/0007.html
self.extra_compile_args.append("-D_WIN32_WINNT=0x0501")
if str.find(sys.version, "MSC") >= 0:
self.extra_compile_args.append("-O2")
self.extra_compile_args.append("-GF") # enable read-only string pooling
self.extra_compile_args.append("-WX") # treat warnings as errors
p = subprocess.Popen(['cl.exe'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
match = re.search(r'Version (\d+)', err.decode().split("\n")[0])
if match and int(match.group(1)) < 16:
# option removed in vs 2010:
# connect.microsoft.com/VisualStudio/feedback/details/475896/link-fatal-error-lnk1117-syntax-error-in-option-opt-nowin98/
self.extra_link_args.append("/opt:nowin98") # use small section alignment
if sys.platform == "win32":
configure = configure_windows
else:
configure = configure_unix
def check_avoid_stdio(self):
if 'PYCURL_SETUP_OPTIONS' in os.environ and '--avoid-stdio' in os.environ['PYCURL_SETUP_OPTIONS']:
self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
if scan_argv(self.argv, '--avoid-stdio') is not None:
self.extra_compile_args.append("-DPYCURL_AVOID_STDIO")
def get_curl_version_info(self, dll_path):
import ctypes
class curl_version_info_struct(ctypes.Structure):
_fields_ = [
('age', ctypes.c_int),
('version', ctypes.c_char_p),
('version_num', ctypes.c_uint),
('host', ctypes.c_char_p),
('features', ctypes.c_int),
('ssl_version', ctypes.c_char_p),
('ssl_version_num', ctypes.c_long),
('libz_version', ctypes.c_char_p),
('protocols', ctypes.c_void_p),
('ares', ctypes.c_char_p),
('ares_num', ctypes.c_int),
('libidn', ctypes.c_char_p),
('iconv_ver_num', ctypes.c_int),
('libssh_version', ctypes.c_char_p),
]
dll = ctypes.CDLL(dll_path)
fn = dll.curl_version_info
fn.argtypes = [ctypes.c_int]
fn.restype = ctypes.POINTER(curl_version_info_struct)
# current version is 3
return fn(3)[0]
def using_openssl(self):
self.define_macros.append(('HAVE_CURL_OPENSSL', 1))
if sys.platform == "win32":
# CRYPTO_num_locks is defined in libeay32.lib
# for openssl < 1.1.0; it is a noop for openssl >= 1.1.0
self.extra_link_args.append(self.openssl_lib_name)
else:
# the actual library that defines CRYPTO_num_locks etc.
# is crypto, and on cygwin linking against ssl does not
# link against crypto as of May 2014.
# http://stackoverflow.com/questions/23687488/cant-get-pycurl-to-install-on-cygwin-missing-openssl-symbols-crypto-num-locks
self.libraries.append('crypto')
# we also need ssl for the certificate functions
# (SSL_CTX_get_cert_store)
self.libraries.append('ssl')
self.define_macros.append(('HAVE_CURL_SSL', 1))
def using_gnutls(self):
self.define_macros.append(('HAVE_CURL_GNUTLS', 1))
self.libraries.append('gnutls')
self.define_macros.append(('HAVE_CURL_SSL', 1))
def using_nss(self):
self.define_macros.append(('HAVE_CURL_NSS', 1))
self.libraries.append('ssl3')
self.define_macros.append(('HAVE_CURL_SSL', 1))
def get_bdist_msi_version_hack():
# workaround for distutils/msi version requirement per
# epydoc.sourceforge.net/stdlib/distutils.version.StrictVersion-class.html -
# only x.y.z version numbers are supported, whereas our versions might be x.y.z.p.
# bugs.python.org/issue6040#msg133094
from distutils.command.bdist_msi import bdist_msi
import inspect
import types
import re
class bdist_msi_version_hack(bdist_msi):
""" MSI builder requires version to be in the x.x.x format """
def run(self):
def monkey_get_version(self):
""" monkey patch replacement for metadata.get_version() that
returns MSI compatible version string for bdist_msi
"""
# get filename of the calling function
if inspect.stack()[1][1].endswith('bdist_msi.py'):
# strip revision from version (if any), e.g. 11.0.0-r31546
match = re.match(r'(\d+\.\d+\.\d+)', self.version)
assert match
return match.group(1)
else:
return self.version
# monkeypatching get_version() call for DistributionMetadata
self.distribution.metadata.get_version = \
types.MethodType(monkey_get_version, self.distribution.metadata)
bdist_msi.run(self)
return bdist_msi_version_hack
def strip_pycurl_options(argv):
if sys.platform == 'win32':
options = [
'--curl-dir=', '--libcurl-lib-name=', '--use-libcurl-dll',
'--avoid-stdio', '--with-openssl',
]
else:
options = ['--openssl-dir=', '--curl-config=', '--avoid-stdio']
for option in options:
scan_argv(argv, option)
###############################################################################
def get_extension(argv, split_extension_source=False):
if split_extension_source:
sources = [
os.path.join("src", "docstrings.c"),
os.path.join("src", "easy.c"),
os.path.join("src", "easycb.c"),
os.path.join("src", "easyinfo.c"),
os.path.join("src", "easyopt.c"),
os.path.join("src", "easyperform.c"),
os.path.join("src", "module.c"),
os.path.join("src", "multi.c"),
os.path.join("src", "oscompat.c"),
os.path.join("src", "pythoncompat.c"),
os.path.join("src", "share.c"),
os.path.join("src", "stringcompat.c"),
os.path.join("src", "threadsupport.c"),
os.path.join("src", "util.c"),
]
depends = [
os.path.join("src", "pycurl.h"),
]
else:
sources = [
os.path.join("src", "allpycurl.c"),
]
depends = []
ext_config = ExtensionConfiguration(argv)
ext = Extension(
name=PACKAGE,
sources=sources,
depends=depends,
include_dirs=ext_config.include_dirs,
define_macros=ext_config.define_macros,
library_dirs=ext_config.library_dirs,
libraries=ext_config.libraries,
runtime_library_dirs=ext_config.runtime_library_dirs,
extra_objects=ext_config.extra_objects,
extra_compile_args=ext_config.extra_compile_args,
extra_link_args=ext_config.extra_link_args,
)
##print(ext.__dict__); sys.exit(1)
return ext
###############################################################################
# prepare data_files
def get_data_files():
# a list of tuples with (path to install to, a list of local files)
data_files = []
if sys.platform == "win32":
datadir = os.path.join("doc", PACKAGE)
else:
datadir = os.path.join("share", "doc", PACKAGE)
#
files = ["AUTHORS", "ChangeLog", "COPYING-LGPL", "COPYING-MIT",
"INSTALL.rst", "README.rst", "RELEASE-NOTES.rst"]
if files:
data_files.append((os.path.join(datadir), files))
files = glob.glob(os.path.join("examples", "*.py"))
if files:
data_files.append((os.path.join(datadir, "examples"), files))
files = glob.glob(os.path.join("examples", "quickstart", "*.py"))
if files:
data_files.append((os.path.join(datadir, "examples", "quickstart"), files))
#
assert data_files
for install_dir, files in data_files:
assert files
for f in files:
assert os.path.isfile(f), (f, install_dir)
return data_files
###############################################################################
def check_manifest():
import fnmatch
f = open('MANIFEST.in')
globs = []
try:
for line in f.readlines():
stripped = line.strip()
if stripped == '' or stripped.startswith('#'):
continue
assert stripped.startswith('include ')
glob = stripped[8:]
globs.append(glob)
finally:
f.close()
paths = []
start = os.path.abspath(os.path.dirname(__file__))
for root, dirs, files in os.walk(start):
if '.git' in dirs:
dirs.remove('.git')
for file in files:
if file.endswith('.pyc'):
continue
rel = os.path.join(root, file)[len(start)+1:]
paths.append(rel)
for path in paths:
included = False
for glob in globs:
if fnmatch.fnmatch(path, glob):
included = True
break
if not included:
print(path)
AUTHORS_PARAGRAPH = 3
def check_authors():
f = open('AUTHORS')
try:
contents = f.read()
finally:
f.close()
paras = contents.split("\n\n")
authors_para = paras[AUTHORS_PARAGRAPH]
authors = [author for author in authors_para.strip().split("\n")]
log = subprocess.check_output(['git', 'log', '--format=%an (%ae)'])
for author in log.strip().split("\n"):
author = author.replace('@', ' at ').replace('(', '<').replace(')', '>')
if author not in authors:
authors.append(author)
authors.sort()
paras[AUTHORS_PARAGRAPH] = "\n".join(authors)
f = open('AUTHORS', 'w')
try:
f.write("\n\n".join(paras))
finally:
f.close()
def convert_docstrings():
docstrings = []
for entry in sorted(os.listdir('doc/docstrings')):
if not entry.endswith('.rst'):
continue
name = entry.replace('.rst', '')
f = open('doc/docstrings/%s' % entry)
try:
text = f.read().strip()
finally:
f.close()
docstrings.append((name, text))
f = open('src/docstrings.c', 'w')
try:
f.write("/* Generated file - do not edit. */\n")
# space to avoid having /* inside a C comment
f.write("/* See doc/docstrings/ *.rst. */\n\n")
f.write("#include \"pycurl.h\"\n\n")
for name, text in docstrings:
text = text.replace("\"", "\\\"").replace("\n", "\\n\\\n")
f.write("PYCURL_INTERNAL const char %s_doc[] = \"%s\";\n\n" % (name, text))
finally:
f.close()
f = open('src/docstrings.h', 'w')
try:
f.write("/* Generated file - do not edit. */\n")
# space to avoid having /* inside a C comment
f.write("/* See doc/docstrings/ *.rst. */\n\n")
for name, text in docstrings:
f.write("extern const char %s_doc[];\n" % name)
finally:
f.close()
def gen_docstrings_sources():
sources = 'DOCSTRINGS_SOURCES ='
for entry in sorted(os.listdir('doc/docstrings')):
if entry.endswith('.rst'):
sources += " \\\n\tdoc/docstrings/%s" % entry
print(sources)
###############################################################################
setup_args = dict(
name=PACKAGE,
version=VERSION,
description='PycURL -- A Python Interface To The cURL library',
long_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 2.7 or 3.4 through 3.6.
- libcurl 7.19.0 or better.
Installation
------------
Download source and binary distributions from `PyPI`_ or `Bintray`_.
Binary wheels are now available for 32 and 64 bit Windows versions.
Please see `the installation documentation`_ for installation instructions.
.. _PyPI: https://pypi.python.org/pypi/pycurl
.. _Bintray: https://dl.bintray.com/pycurl/pycurl/
.. _the installation documentation: http://pycurl.io/docs/latest/install.html
Documentation
-------------
Documentation for the most recent PycURL release is available on
`PycURL website `_.
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
''',
author="Kjetil Jacobsen, Markus F.X.J. Oberhumer, Oleg Pudeyev",
author_email="kjetilja at gmail.com, markus at oberhumer.com, oleg at bsdpower.com",
maintainer="Oleg Pudeyev",
maintainer_email="oleg@bsdpower.com",
url="http://pycurl.io/",
license="LGPL/MIT",
keywords=['curl', 'libcurl', 'urllib', 'wget', 'download', 'file transfer',
'http', 'www'],
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
'Intended Audience :: Developers',
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
'License :: OSI Approved :: MIT License',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Internet :: File Transfer Protocol (FTP)',
'Topic :: Internet :: WWW/HTTP',
],
packages=[PY_PACKAGE],
package_dir={ PY_PACKAGE: os.path.join('python', 'curl') },
)
if sys.platform == "win32":
setup_args['cmdclass'] = {'bdist_msi': get_bdist_msi_version_hack()}
##print distutils.__version__
if LooseVersion(distutils.__version__) > LooseVersion("1.0.1"):
setup_args["platforms"] = "All"
if LooseVersion(distutils.__version__) < LooseVersion("1.0.3"):
setup_args["licence"] = setup_args["license"]
unix_help = '''\
PycURL Unix options:
--curl-config=/path/to/curl-config use specified curl-config binary
--libcurl-dll=[/path/to/]libcurl.so obtain SSL library from libcurl.so
--openssl-dir=/path/to/openssl/dir path to OpenSSL headers and libraries
--with-openssl libcurl is linked against OpenSSL
--with-ssl legacy alias for --with-openssl
--with-gnutls libcurl is linked against GnuTLS
--with-nss libcurl is linked against NSS
'''
windows_help = '''\
PycURL Windows options:
--curl-dir=/path/to/compiled/libcurl path to libcurl headers and libraries
--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
--with-openssl libcurl is linked against OpenSSL
--with-ssl legacy alias for --with-openssl
--link-arg=foo.lib also link against specified library
'''
if __name__ == "__main__":
if '--help' in sys.argv or '-h' in sys.argv:
# unfortunately this help precedes distutils help
if sys.platform == "win32":
print(windows_help)
else:
print(unix_help)
# invoke setup without configuring pycurl because
# configuration might fail, and we want to display help anyway.
# we need to remove our options because distutils complains about them
strip_pycurl_options(sys.argv)
setup(**setup_args)
elif len(sys.argv) > 1 and sys.argv[1] == 'manifest':
check_manifest()
elif len(sys.argv) > 1 and sys.argv[1] == 'docstrings':
convert_docstrings()
elif len(sys.argv) > 1 and sys.argv[1] == 'authors':
check_authors()
elif len(sys.argv) > 1 and sys.argv[1] == 'docstrings-sources':
gen_docstrings_sources()
else:
setup_args['data_files'] = get_data_files()
if 'PYCURL_RELEASE' in os.environ and os.environ['PYCURL_RELEASE'].lower() in ['1', 'yes', 'true']:
split_extension_source = False
else:
split_extension_source = True
ext = get_extension(sys.argv, split_extension_source=split_extension_source)
setup_args['ext_modules'] = [ext]
for o in ext.extra_objects:
assert os.path.isfile(o), o
setup(**setup_args)
pycurl-7.43.0.2/setup.cfg 0000644 0001750 0001750 00000000046 13304422066 014130 0 ustar me me 0000000 0000000 [egg_info]
tag_build =
tag_date = 0
pycurl-7.43.0.2/README.rst 0000644 0001750 0001750 00000014655 13304422026 014005 0 ustar me me 0000000 0000000 PycURL -- A Python Interface To The cURL library
================================================
.. image:: https://api.travis-ci.org/pycurl/pycurl.png
:target: https://travis-ci.org/pycurl/pycurl
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 2.7 or 3.4 through 3.6.
- libcurl 7.19.0 or better.
Installation
------------
Download source and binary distributions from `PyPI`_ or `Bintray`_.
Binary wheels are now available for 32 and 64 bit Windows versions.
Please see `INSTALL.rst`_ for installation instructions. If installing from
a Git checkout, please follow instruction in the `Git Checkout`_ section
of INSTALL.rst.
.. _PyPI: https://pypi.python.org/pypi/pycurl
.. _Bintray: https://dl.bintray.com/pycurl/pycurl/
.. _INSTALL.rst: http://pycurl.io/docs/latest/install.html
.. _Git Checkout: http://pycurl.io/docs/latest/install.html#git-checkout
Documentation
-------------
Documentation for the most recent PycURL release is available on
`PycURL website `_.
Documentation for the development version of PycURL
is available `here `_.
To build documentation from source, run ``make docs``.
Building documentation requires `Sphinx `_ to
be installed, as well as pycurl extension module built as docstrings are
extracted from it. Built documentation is stored in ``build/doc``
subdirectory.
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
Automated Tests
---------------
PycURL comes with an automated test suite. To run the tests, execute::
make test
The suite depends on packages `nose`_ and `bottle`_, as well as `vsftpd`_.
Some tests use vsftpd configured to accept anonymous uploads. These tests
are not run by default. As configured, vsftpd will allow reads and writes to
anything the user running the tests has read and write access. To run
vsftpd tests you must explicitly set PYCURL_VSFTPD_PATH variable like so::
# use vsftpd in PATH
export PYCURL_VSFTPD_PATH=vsftpd
# specify full path to vsftpd
export PYCURL_VSFTPD_PATH=/usr/local/libexec/vsftpd
.. _nose: https://nose.readthedocs.org/
.. _bottle: http://bottlepy.org/
.. _vsftpd: http://vsftpd.beasts.org/
Test Matrix
-----------
The test matrix is a separate framework that runs tests on more esoteric
configurations. It supports:
- Testing against Python 2.4, which bottle does not support.
- Testing against Python compiled without threads, which requires an out of
process test server.
- Testing against locally compiled libcurl with arbitrary options.
To use the test matrix, first start the test server from Python 2.5+ by
running::
python -m tests.appmanager
Then in a different shell, and preferably in a separate user account,
run the test matrix::
# run ftp tests, etc.
export PYCURL_VSFTPD_PATH=vsftpd
# create a new work directory, preferably not under pycurl tree
mkdir testmatrix
cd testmatrix
# run the matrix specifying absolute path
python /path/to/pycurl/tests/matrix.py
The test matrix will download, build and install supported Python versions
and supported libcurl versions, then run pycurl tests against each combination.
To see what the combinations are, look in
`tests/matrix.py `_.
Contribute
----------
For smaller changes:
#. Fork `the repository`_ on Github.
#. Create a branch off **master**.
#. Make your changes.
#. Write a test which shows that the bug was fixed or that the feature
works as expected.
#. Send a pull request.
#. Check back after 10-15 minutes to see if tests passed on Travis CI.
PycURL supports old Python and libcurl releases and their support is tested
on Travis.
For larger changes:
#. Join the `mailing list`_.
#. Discuss your proposal on the mailing list.
#. When consensus is reached, implement it as described above.
Please contribute binary distributions for your system to the
`downloads repository`_.
License
-------
::
Copyright (C) 2001-2008 by Kjetil Jacobsen
Copyright (C) 2001-2008 by Markus F.X.J. Oberhumer
Copyright (C) 2013-2018 by Oleg Pudeyev
All rights reserved.
PycURL is dual licensed under the LGPL and an MIT/X derivative license
based on the cURL license. A full copy of the LGPL license is included
in the file COPYING-LGPL. A full copy of the MIT/X derivative license is
included in the file COPYING-MIT. You can redistribute and/or modify PycURL
according to the terms of either license.
.. _PycURL: http://pycurl.io/
.. _libcurl: https://curl.haxx.se/libcurl/
.. _urllib: http://docs.python.org/library/urllib.html
.. _`the repository`: https://github.com/pycurl/pycurl
.. _`mailing list`: http://cool.haxx.se/mailman/listinfo/curl-and-python
.. _`downloads repository`: https://github.com/pycurl/downloads
pycurl-7.43.0.2/src/ 0000755 0001750 0001750 00000000000 13304422066 013076 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/src/util.c 0000644 0001750 0001750 00000001151 13301165576 014224 0 ustar me me 0000000 0000000 #include "pycurl.h"
static PyObject *
create_error_object(CurlObject *self, int code)
{
PyObject *s, *v;
s = PyText_FromString_Ignore(self->error);
if (s == NULL) {
return NULL;
}
v = Py_BuildValue("(iO)", code, s);
if (v == NULL) {
Py_DECREF(s);
return NULL;
}
return v;
}
PYCURL_INTERNAL void
create_and_set_error_object(CurlObject *self, int code)
{
PyObject *e;
self->error[sizeof(self->error) - 1] = 0;
e = create_error_object(self, code);
if (e != NULL) {
PyErr_SetObject(ErrorObject, e);
Py_DECREF(e);
}
}
pycurl-7.43.0.2/src/easycb.c 0000644 0001750 0001750 00000062532 13301173520 014513 0 ustar me me 0000000 0000000 #include "pycurl.h"
/* IMPORTANT NOTE: due to threading issues, we cannot call _any_ Python
* function without acquiring the thread state in the callback handlers.
*/
static size_t
util_write_callback(int flags, char *ptr, size_t size, size_t nmemb, void *stream)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
size_t ret = 0; /* assume error */
PyObject *cb;
int total_size;
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check args */
cb = flags ? self->h_cb : self->w_cb;
if (cb == NULL)
goto silent_error;
if (size <= 0 || nmemb <= 0)
goto done;
total_size = (int)(size * nmemb);
if (total_size < 0 || (size_t)total_size / size != nmemb) {
PyErr_SetString(ErrorObject, "integer overflow in write callback");
goto verbose_error;
}
/* run callback */
#if PY_MAJOR_VERSION >= 3
arglist = Py_BuildValue("(y#)", ptr, total_size);
#else
arglist = Py_BuildValue("(s#)", ptr, total_size);
#endif
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (result == Py_None) {
ret = total_size; /* None means success */
}
else if (PyInt_Check(result) || PyLong_Check(result)) {
/* if the cast to long fails, PyLong_AsLong() returns -1L */
ret = (size_t) PyLong_AsLong(result);
}
else {
PyErr_SetString(ErrorObject, "write callback must return int or None");
goto verbose_error;
}
done:
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
PYCURL_INTERNAL size_t
write_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
return util_write_callback(0, ptr, size, nmemb, stream);
}
PYCURL_INTERNAL size_t
header_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
return util_write_callback(1, ptr, size, nmemb, stream);
}
/* convert protocol address from C to python, returns a tuple of protocol
specific values */
static PyObject *
convert_protocol_address(struct sockaddr* saddr, unsigned int saddrlen)
{
PyObject *res_obj = NULL;
switch (saddr->sa_family)
{
case AF_INET:
{
struct sockaddr_in* sin = (struct sockaddr_in*)saddr;
char *addr_str = PyMem_New(char, INET_ADDRSTRLEN);
if (addr_str == NULL) {
PyErr_NoMemory();
goto error;
}
if (inet_ntop(saddr->sa_family, &sin->sin_addr, addr_str, INET_ADDRSTRLEN) == NULL) {
PyErr_SetFromErrno(ErrorObject);
PyMem_Free(addr_str);
goto error;
}
res_obj = Py_BuildValue("(si)", addr_str, ntohs(sin->sin_port));
PyMem_Free(addr_str);
}
break;
case AF_INET6:
{
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)saddr;
char *addr_str = PyMem_New(char, INET6_ADDRSTRLEN);
if (addr_str == NULL) {
PyErr_NoMemory();
goto error;
}
if (inet_ntop(saddr->sa_family, &sin6->sin6_addr, addr_str, INET6_ADDRSTRLEN) == NULL) {
PyErr_SetFromErrno(ErrorObject);
PyMem_Free(addr_str);
goto error;
}
res_obj = Py_BuildValue("(siii)", addr_str, (int) ntohs(sin6->sin6_port),
(int) ntohl(sin6->sin6_flowinfo), (int) ntohl(sin6->sin6_scope_id));
PyMem_Free(addr_str);
}
break;
#if !defined(WIN32)
case AF_UNIX:
{
struct sockaddr_un* s_un = (struct sockaddr_un*)saddr;
#if PY_MAJOR_VERSION >= 3
res_obj = Py_BuildValue("y", s_un->sun_path);
#else
res_obj = Py_BuildValue("s", s_un->sun_path);
#endif
}
break;
#endif
default:
/* We (currently) only support IPv4/6 addresses. Can curl even be used
with anything else? */
PyErr_SetString(ErrorObject, "Unsupported address family");
}
error:
return res_obj;
}
/* curl_socket_t is just an int on unix/windows (with limitations that
* are not important here) */
PYCURL_INTERNAL curl_socket_t
opensocket_callback(void *clientp, curlsocktype purpose,
struct curl_sockaddr *address)
{
PyObject *arglist;
PyObject *result = NULL;
PyObject *fileno_result = NULL;
CurlObject *self;
int ret = CURL_SOCKET_BAD;
PyObject *converted_address;
PyObject *python_address;
PYCURL_DECLARE_THREAD_STATE;
self = (CurlObject *)clientp;
PYCURL_ACQUIRE_THREAD();
converted_address = convert_protocol_address(&address->addr, address->addrlen);
if (converted_address == NULL) {
goto verbose_error;
}
arglist = Py_BuildValue("(iiiN)", address->family, address->socktype, address->protocol, converted_address);
if (arglist == NULL) {
Py_DECREF(converted_address);
goto verbose_error;
}
python_address = PyEval_CallObject(curl_sockaddr_type, arglist);
Py_DECREF(arglist);
if (python_address == NULL) {
goto verbose_error;
}
arglist = Py_BuildValue("(iN)", purpose, python_address);
if (arglist == NULL) {
Py_DECREF(python_address);
goto verbose_error;
}
result = PyEval_CallObject(self->opensocket_cb, arglist);
Py_DECREF(arglist);
if (result == NULL) {
goto verbose_error;
}
if (PyInt_Check(result) && PyInt_AsLong(result) == CURL_SOCKET_BAD) {
ret = CURL_SOCKET_BAD;
} else if (PyObject_HasAttrString(result, "fileno")) {
fileno_result = PyObject_CallMethod(result, "fileno", NULL);
if (fileno_result == NULL) {
ret = CURL_SOCKET_BAD;
goto verbose_error;
}
// normal operation:
if (PyInt_Check(fileno_result)) {
int sockfd = PyInt_AsLong(fileno_result);
#if defined(WIN32)
ret = dup_winsock(sockfd, address);
#else
ret = dup(sockfd);
#endif
goto done;
} else {
PyErr_SetString(ErrorObject, "Open socket callback returned an object whose fileno method did not return an integer");
ret = CURL_SOCKET_BAD;
}
} else {
PyErr_SetString(ErrorObject, "Open socket callback's return value must be a socket");
ret = CURL_SOCKET_BAD;
goto verbose_error;
}
silent_error:
done:
Py_XDECREF(result);
Py_XDECREF(fileno_result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
PYCURL_INTERNAL int
sockopt_cb(void *clientp, curl_socket_t curlfd, curlsocktype purpose)
{
PyObject *arglist;
CurlObject *self;
int ret = -1;
PyObject *ret_obj = NULL;
PYCURL_DECLARE_THREAD_STATE;
self = (CurlObject *)clientp;
PYCURL_ACQUIRE_THREAD();
arglist = Py_BuildValue("(ii)", (int) curlfd, (int) purpose);
if (arglist == NULL)
goto verbose_error;
ret_obj = PyEval_CallObject(self->sockopt_cb, arglist);
Py_DECREF(arglist);
if (!PyInt_Check(ret_obj) && !PyLong_Check(ret_obj)) {
PyObject *ret_repr = PyObject_Repr(ret_obj);
if (ret_repr) {
PyObject *encoded_obj;
char *str = PyText_AsString_NoNUL(ret_repr, &encoded_obj);
fprintf(stderr, "sockopt callback returned %s which is not an integer\n", str);
/* PyErr_Format(PyExc_TypeError, "sockopt callback returned %s which is not an integer", str); */
Py_XDECREF(encoded_obj);
Py_DECREF(ret_repr);
}
goto silent_error;
}
if (PyInt_Check(ret_obj)) {
/* long to int cast */
ret = (int) PyInt_AsLong(ret_obj);
} else {
/* long to int cast */
ret = (int) PyLong_AsLong(ret_obj);
}
goto done;
silent_error:
ret = -1;
done:
Py_XDECREF(ret_obj);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
PYCURL_INTERNAL int
closesocket_callback(void *clientp, curl_socket_t curlfd)
{
PyObject *arglist;
CurlObject *self;
int ret = -1;
PyObject *ret_obj = NULL;
PYCURL_DECLARE_THREAD_STATE;
self = (CurlObject *)clientp;
PYCURL_ACQUIRE_THREAD();
arglist = Py_BuildValue("(i)", (int) curlfd);
if (arglist == NULL)
goto verbose_error;
ret_obj = PyEval_CallObject(self->closesocket_cb, arglist);
Py_DECREF(arglist);
if (!ret_obj)
goto silent_error;
if (!PyInt_Check(ret_obj) && !PyLong_Check(ret_obj)) {
PyObject *ret_repr = PyObject_Repr(ret_obj);
if (ret_repr) {
PyObject *encoded_obj;
char *str = PyText_AsString_NoNUL(ret_repr, &encoded_obj);
fprintf(stderr, "closesocket callback returned %s which is not an integer\n", str);
/* PyErr_Format(PyExc_TypeError, "closesocket callback returned %s which is not an integer", str); */
Py_XDECREF(encoded_obj);
Py_DECREF(ret_repr);
}
goto silent_error;
}
if (PyInt_Check(ret_obj)) {
/* long to int cast */
ret = (int) PyInt_AsLong(ret_obj);
} else {
/* long to int cast */
ret = (int) PyLong_AsLong(ret_obj);
}
goto done;
silent_error:
ret = -1;
done:
Py_XDECREF(ret_obj);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#endif
#ifdef HAVE_CURL_7_19_6_OPTS
static PyObject *
khkey_to_object(const struct curl_khkey *khkey)
{
PyObject *arglist, *ret;
if (khkey == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
if (khkey->len) {
#if PY_MAJOR_VERSION >= 3
arglist = Py_BuildValue("(y#i)", khkey->key, khkey->len, khkey->keytype);
#else
arglist = Py_BuildValue("(s#i)", khkey->key, khkey->len, khkey->keytype);
#endif
} else {
#if PY_MAJOR_VERSION >= 3
arglist = Py_BuildValue("(yi)", khkey->key, khkey->keytype);
#else
arglist = Py_BuildValue("(si)", khkey->key, khkey->keytype);
#endif
}
if (arglist == NULL) {
return NULL;
}
ret = PyObject_Call(khkey_type, arglist, NULL);
Py_DECREF(arglist);
return ret;
}
PYCURL_INTERNAL int
ssh_key_cb(CURL *easy, const struct curl_khkey *knownkey,
const struct curl_khkey *foundkey, int khmatch, void *clientp)
{
PyObject *arglist;
CurlObject *self;
int ret = -1;
PyObject *knownkey_obj = NULL;
PyObject *foundkey_obj = NULL;
PyObject *ret_obj = NULL;
PYCURL_DECLARE_THREAD_STATE;
self = (CurlObject *)clientp;
PYCURL_ACQUIRE_THREAD();
knownkey_obj = khkey_to_object(knownkey);
if (knownkey_obj == NULL) {
goto silent_error;
}
foundkey_obj = khkey_to_object(foundkey);
if (foundkey_obj == NULL) {
goto silent_error;
}
arglist = Py_BuildValue("(OOi)", knownkey_obj, foundkey_obj, khmatch);
if (arglist == NULL)
goto verbose_error;
ret_obj = PyEval_CallObject(self->ssh_key_cb, arglist);
Py_DECREF(arglist);
if (!PyInt_Check(ret_obj) && !PyLong_Check(ret_obj)) {
PyObject *ret_repr = PyObject_Repr(ret_obj);
if (ret_repr) {
PyObject *encoded_obj;
char *str = PyText_AsString_NoNUL(ret_repr, &encoded_obj);
fprintf(stderr, "ssh key callback returned %s which is not an integer\n", str);
/* PyErr_Format(PyExc_TypeError, "ssh key callback returned %s which is not an integer", str); */
Py_XDECREF(encoded_obj);
Py_DECREF(ret_repr);
}
goto silent_error;
}
if (PyInt_Check(ret_obj)) {
/* long to int cast */
ret = (int) PyInt_AsLong(ret_obj);
} else {
/* long to int cast */
ret = (int) PyLong_AsLong(ret_obj);
}
goto done;
silent_error:
ret = -1;
done:
Py_XDECREF(knownkey_obj);
Py_XDECREF(foundkey_obj);
Py_XDECREF(ret_obj);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#endif
PYCURL_INTERNAL int
seek_callback(void *stream, curl_off_t offset, int origin)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = 2; /* assume error 2 (can't seek, libcurl free to work around). */
PyObject *cb;
int source = 0; /* assume beginning */
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check arguments */
switch (origin)
{
case SEEK_SET:
source = 0;
break;
case SEEK_CUR:
source = 1;
break;
case SEEK_END:
source = 2;
break;
default:
source = origin;
break;
}
/* run callback */
cb = self->seek_cb;
if (cb == NULL)
goto silent_error;
arglist = Py_BuildValue("(i,i)", offset, source);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (result == Py_None) {
ret = 0; /* None means success */
}
else if (PyInt_Check(result)) {
int ret_code = PyInt_AsLong(result);
if (ret_code < 0 || ret_code > 2) {
PyErr_Format(ErrorObject, "invalid return value for seek callback %d not in (0, 1, 2)", ret_code);
goto verbose_error;
}
ret = ret_code; /* pass the return code from the callback */
}
else {
PyErr_SetString(ErrorObject, "seek callback must return 0 (CURL_SEEKFUNC_OK), 1 (CURL_SEEKFUNC_FAIL), 2 (CURL_SEEKFUNC_CANTSEEK) or None");
goto verbose_error;
}
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
PYCURL_INTERNAL size_t
read_callback(char *ptr, size_t size, size_t nmemb, void *stream)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
size_t ret = CURL_READFUNC_ABORT; /* assume error, this actually works */
int total_size;
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check args */
if (self->r_cb == NULL)
goto silent_error;
if (size <= 0 || nmemb <= 0)
goto done;
total_size = (int)(size * nmemb);
if (total_size < 0 || (size_t)total_size / size != nmemb) {
PyErr_SetString(ErrorObject, "integer overflow in read callback");
goto verbose_error;
}
/* run callback */
arglist = Py_BuildValue("(i)", total_size);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->r_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (PyByteStr_Check(result)) {
char *buf = NULL;
Py_ssize_t obj_size = -1;
Py_ssize_t r;
r = PyByteStr_AsStringAndSize(result, &buf, &obj_size);
if (r != 0 || obj_size < 0 || obj_size > total_size) {
PyErr_Format(ErrorObject, "invalid return value for read callback (%ld bytes returned when at most %ld bytes were wanted)", (long)obj_size, (long)total_size);
goto verbose_error;
}
memcpy(ptr, buf, obj_size);
ret = obj_size; /* success */
}
else if (PyUnicode_Check(result)) {
char *buf = NULL;
Py_ssize_t obj_size = -1;
Py_ssize_t r;
/*
Encode with ascii codec.
HTTP requires sending content-length for request body to the server
before the request body is sent, therefore typically content length
is given via POSTFIELDSIZE before read function is invoked to
provide the data.
However, if we encode the string using any encoding other than ascii,
the length of encoded string may not match the length of unicode
string we are encoding. Therefore, if client code does a simple
len(source_string) to determine the value to supply in content-length,
the length of bytes read may be different.
To avoid this situation, we only accept ascii bytes in the string here.
Encode data yourself to bytes when dealing with non-ascii data.
*/
PyObject *encoded = PyUnicode_AsEncodedString(result, "ascii", "strict");
if (encoded == NULL) {
goto verbose_error;
}
r = PyByteStr_AsStringAndSize(encoded, &buf, &obj_size);
if (r != 0 || obj_size < 0 || obj_size > total_size) {
Py_DECREF(encoded);
PyErr_Format(ErrorObject, "invalid return value for read callback (%ld bytes returned after encoding to utf-8 when at most %ld bytes were wanted)", (long)obj_size, (long)total_size);
goto verbose_error;
}
memcpy(ptr, buf, obj_size);
Py_DECREF(encoded);
ret = obj_size; /* success */
}
#if PY_MAJOR_VERSION < 3
else if (PyInt_Check(result)) {
long r = PyInt_AsLong(result);
if (r != CURL_READFUNC_ABORT && r != CURL_READFUNC_PAUSE)
goto type_error;
ret = r; /* either CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE */
}
#endif
else if (PyLong_Check(result)) {
long r = PyLong_AsLong(result);
if (r != CURL_READFUNC_ABORT && r != CURL_READFUNC_PAUSE)
goto type_error;
ret = r; /* either CURL_READFUNC_ABORT or CURL_READFUNC_PAUSE */
}
else {
type_error:
PyErr_SetString(ErrorObject, "read callback must return a byte string or Unicode string with ASCII code points only");
goto verbose_error;
}
done:
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
PYCURL_INTERNAL int
progress_callback(void *stream,
double dltotal, double dlnow, double ultotal, double ulnow)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = 1; /* assume error */
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check args */
if (self->pro_cb == NULL)
goto silent_error;
/* run callback */
arglist = Py_BuildValue("(dddd)", dltotal, dlnow, ultotal, ulnow);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->pro_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (result == Py_None) {
ret = 0; /* None means success */
}
else if (PyInt_Check(result)) {
ret = (int) PyInt_AsLong(result);
}
else {
ret = PyObject_IsTrue(result); /* FIXME ??? */
}
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
PYCURL_INTERNAL int
xferinfo_callback(void *stream,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = 1; /* assume error */
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check args */
if (self->xferinfo_cb == NULL)
goto silent_error;
/* run callback */
arglist = Py_BuildValue("(LLLL)",
(PY_LONG_LONG) dltotal, (PY_LONG_LONG) dlnow,
(PY_LONG_LONG) ultotal, (PY_LONG_LONG) ulnow);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->xferinfo_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (result == Py_None) {
ret = 0; /* None means success */
}
else if (PyInt_Check(result)) {
ret = (int) PyInt_AsLong(result);
}
else {
ret = PyObject_IsTrue(result); /* FIXME ??? */
}
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#endif
PYCURL_INTERNAL int
debug_callback(CURL *curlobj, curl_infotype type,
char *buffer, size_t total_size, void *stream)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = 0; /* always success */
PYCURL_DECLARE_THREAD_STATE;
UNUSED(curlobj);
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return ret;
/* check args */
if (self->debug_cb == NULL)
goto silent_error;
if ((int)total_size < 0 || (size_t)((int)total_size) != total_size) {
PyErr_SetString(ErrorObject, "integer overflow in debug callback");
goto verbose_error;
}
/* run callback */
#if PY_MAJOR_VERSION >= 3
arglist = Py_BuildValue("(iy#)", (int)type, buffer, (int)total_size);
#else
arglist = Py_BuildValue("(is#)", (int)type, buffer, (int)total_size);
#endif
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->debug_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* return values from debug callbacks should be ignored */
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
PYCURL_INTERNAL curlioerr
ioctl_callback(CURL *curlobj, int cmd, void *stream)
{
CurlObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = CURLIOE_FAILRESTART; /* assume error */
PYCURL_DECLARE_THREAD_STATE;
UNUSED(curlobj);
/* acquire thread */
self = (CurlObject *)stream;
if (!PYCURL_ACQUIRE_THREAD())
return (curlioerr) ret;
/* check args */
if (self->ioctl_cb == NULL)
goto silent_error;
/* run callback */
arglist = Py_BuildValue("(i)", cmd);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->ioctl_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* handle result */
if (result == Py_None) {
ret = CURLIOE_OK; /* None means success */
}
else if (PyInt_Check(result)) {
ret = (int) PyInt_AsLong(result);
if (ret >= CURLIOE_LAST || ret < 0) {
PyErr_SetString(ErrorObject, "ioctl callback returned invalid value");
goto verbose_error;
}
}
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return (curlioerr) ret;
verbose_error:
PyErr_Print();
goto silent_error;
}
#if defined(HAVE_CURL_OPENSSL)
/* internal helper that load certificates from buffer, returns -1 on error */
static int
add_ca_certs(SSL_CTX *context, void *data, Py_ssize_t len)
{
// this code was copied from _ssl module
BIO *biobuf = NULL;
X509_STORE *store;
int retval = 0, err, loaded = 0;
if (len <= 0) {
PyErr_SetString(PyExc_ValueError,
"Empty certificate data");
return -1;
} else if (len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"Certificate data is too long.");
return -1;
}
biobuf = BIO_new_mem_buf(data, (int)len);
if (biobuf == NULL) {
PyErr_SetString(PyExc_MemoryError, "Can't allocate buffer");
ERR_clear_error();
return -1;
}
store = SSL_CTX_get_cert_store(context);
assert(store != NULL);
while (1) {
X509 *cert = NULL;
int r;
cert = PEM_read_bio_X509(biobuf, NULL, 0, NULL);
if (cert == NULL) {
break;
}
r = X509_STORE_add_cert(store, cert);
X509_free(cert);
if (!r) {
err = ERR_peek_last_error();
if ((ERR_GET_LIB(err) == ERR_LIB_X509) &&
(ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE)) {
/* cert already in hash table, not an error */
ERR_clear_error();
} else {
break;
}
}
loaded++;
}
err = ERR_peek_last_error();
if ((loaded > 0) &&
(ERR_GET_LIB(err) == ERR_LIB_PEM) &&
(ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
/* EOF PEM file, not an error */
ERR_clear_error();
retval = 0;
} else {
PyErr_SetString(ErrorObject, ERR_reason_error_string(err));
ERR_clear_error();
retval = -1;
}
BIO_free(biobuf);
return retval;
}
PYCURL_INTERNAL CURLcode
ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *ptr)
{
CurlObject *self;
PYCURL_DECLARE_THREAD_STATE;
int r;
UNUSED(curl);
/* acquire thread */
self = (CurlObject *)ptr;
if (!PYCURL_ACQUIRE_THREAD())
return CURLE_FAILED_INIT;
r = add_ca_certs((SSL_CTX*)ssl_ctx,
PyBytes_AS_STRING(self->ca_certs_obj),
PyBytes_GET_SIZE(self->ca_certs_obj));
if (r != 0)
PyErr_Print();
PYCURL_RELEASE_THREAD();
return r == 0 ? CURLE_OK : CURLE_FAILED_INIT;
}
#endif
pycurl-7.43.0.2/src/module.c 0000644 0001750 0001750 00000161022 13301332107 014522 0 ustar me me 0000000 0000000 #include "pycurl.h"
#include "docstrings.h"
#if defined(WIN32)
# define PYCURL_STRINGIZE_IMP(x) #x
# define PYCURL_STRINGIZE(x) PYCURL_STRINGIZE_IMP(x)
# define PYCURL_VERSION_STRING PYCURL_STRINGIZE(PYCURL_VERSION)
#else
# define PYCURL_VERSION_STRING PYCURL_VERSION
#endif
#define PYCURL_VERSION_PREFIX "PycURL/" PYCURL_VERSION_STRING
PYCURL_INTERNAL char *empty_keywords[] = { NULL };
PYCURL_INTERNAL PyObject *bytesio = NULL;
PYCURL_INTERNAL PyObject *stringio = NULL;
/* Initialized during module init */
PYCURL_INTERNAL char *g_pycurl_useragent = NULL;
/* Type objects */
PYCURL_INTERNAL PyObject *ErrorObject = NULL;
PYCURL_INTERNAL PyTypeObject *p_Curl_Type = NULL;
PYCURL_INTERNAL PyTypeObject *p_CurlMulti_Type = NULL;
PYCURL_INTERNAL PyTypeObject *p_CurlShare_Type = NULL;
#ifdef HAVE_CURL_7_19_6_OPTS
PYCURL_INTERNAL PyObject *khkey_type = NULL;
#endif
PYCURL_INTERNAL PyObject *curl_sockaddr_type = NULL;
PYCURL_INTERNAL PyObject *curlobject_constants = NULL;
PYCURL_INTERNAL PyObject *curlmultiobject_constants = NULL;
PYCURL_INTERNAL PyObject *curlshareobject_constants = NULL;
/* List of functions defined in this module */
static PyMethodDef curl_methods[] = {
{"global_init", (PyCFunction)do_global_init, METH_VARARGS, pycurl_global_init_doc},
{"global_cleanup", (PyCFunction)do_global_cleanup, METH_NOARGS, pycurl_global_cleanup_doc},
{"version_info", (PyCFunction)do_version_info, METH_VARARGS, pycurl_version_info_doc},
{NULL, NULL, 0, NULL}
};
/*************************************************************************
// module level
// Note that the object constructors (do_curl_new, do_multi_new)
// are module-level functions as well.
**************************************************************************/
static int
are_global_init_flags_valid(int flags)
{
#ifdef CURL_GLOBAL_ACK_EINTR
/* CURL_GLOBAL_ACK_EINTR was introduced in libcurl-7.30.0 */
return !(flags & ~(CURL_GLOBAL_ALL | CURL_GLOBAL_ACK_EINTR));
#else
return !(flags & ~(CURL_GLOBAL_ALL));
#endif
}
PYCURL_INTERNAL PyObject *
do_global_init(PyObject *dummy, PyObject *args)
{
int res, option;
UNUSED(dummy);
if (!PyArg_ParseTuple(args, "i:global_init", &option)) {
return NULL;
}
if (!are_global_init_flags_valid(option)) {
PyErr_SetString(PyExc_ValueError, "invalid option to global_init");
return NULL;
}
res = curl_global_init(option);
if (res != CURLE_OK) {
PyErr_SetString(ErrorObject, "unable to set global option");
return NULL;
}
Py_RETURN_NONE;
}
PYCURL_INTERNAL PyObject *
do_global_cleanup(PyObject *dummy)
{
UNUSED(dummy);
curl_global_cleanup();
#ifdef PYCURL_NEED_SSL_TSL
pycurl_ssl_cleanup();
#endif
Py_RETURN_NONE;
}
static PyObject *vi_str(const char *s)
{
if (s == NULL)
Py_RETURN_NONE;
while (*s == ' ' || *s == '\t')
s++;
return PyText_FromString(s);
}
PYCURL_INTERNAL PyObject *
do_version_info(PyObject *dummy, PyObject *args)
{
const curl_version_info_data *vi;
PyObject *ret = NULL;
PyObject *protocols = NULL;
PyObject *tmp;
Py_ssize_t i;
int stamp = CURLVERSION_NOW;
UNUSED(dummy);
if (!PyArg_ParseTuple(args, "|i:version_info", &stamp)) {
return NULL;
}
vi = curl_version_info((CURLversion) stamp);
if (vi == NULL) {
PyErr_SetString(ErrorObject, "unable to get version info");
return NULL;
}
/* INFO: actually libcurl in lib/version.c does ignore
* the "stamp" parameter, and so do we. */
for (i = 0; vi->protocols[i] != NULL; )
i++;
protocols = PyTuple_New(i);
if (protocols == NULL)
goto error;
for (i = 0; vi->protocols[i] != NULL; i++) {
tmp = vi_str(vi->protocols[i]);
if (tmp == NULL)
goto error;
PyTuple_SET_ITEM(protocols, i, tmp);
}
ret = PyTuple_New((Py_ssize_t)12);
if (ret == NULL)
goto error;
#define SET(i, v) \
tmp = (v); if (tmp == NULL) goto error; PyTuple_SET_ITEM(ret, i, tmp)
SET(0, PyInt_FromLong((long) vi->age));
SET(1, vi_str(vi->version));
SET(2, PyInt_FromLong(vi->version_num));
SET(3, vi_str(vi->host));
SET(4, PyInt_FromLong(vi->features));
SET(5, vi_str(vi->ssl_version));
SET(6, PyInt_FromLong(vi->ssl_version_num));
SET(7, vi_str(vi->libz_version));
SET(8, protocols);
SET(9, vi_str(vi->ares));
SET(10, PyInt_FromLong(vi->ares_num));
SET(11, vi_str(vi->libidn));
#undef SET
return ret;
error:
Py_XDECREF(ret);
Py_XDECREF(protocols);
return NULL;
}
/* Helper functions for inserting constants into the module namespace */
static int
insobj2(PyObject *dict1, PyObject *dict2, char *name, PyObject *value)
{
/* Insert an object into one or two dicts. Eats a reference to value.
* See also the implementation of PyDict_SetItemString(). */
PyObject *key = NULL;
if (dict1 == NULL && dict2 == NULL)
goto error;
if (value == NULL)
goto error;
key = PyText_FromString(name);
if (key == NULL)
goto error;
#if 0
PyString_InternInPlace(&key); /* XXX Should we really? */
#endif
if (dict1 != NULL) {
#if !defined(NDEBUG)
if (PyDict_GetItem(dict1, key) != NULL) {
fprintf(stderr, "Symbol already defined: %s\n", name);
assert(0);
}
#endif
if (PyDict_SetItem(dict1, key, value) != 0)
goto error;
}
if (dict2 != NULL && dict2 != dict1) {
assert(PyDict_GetItem(dict2, key) == NULL);
if (PyDict_SetItem(dict2, key, value) != 0)
goto error;
}
Py_DECREF(key);
Py_DECREF(value);
return 0;
error:
Py_XDECREF(key);
return -1;
}
#define insobj2_modinit(dict1, dict2, name, value) \
if (insobj2(dict1, dict2, name, value) < 0) \
goto error
static int
insstr(PyObject *d, char *name, char *value)
{
PyObject *v;
int rv;
v = PyText_FromString(value);
if (v == NULL)
return -1;
rv = insobj2(d, NULL, name, v);
if (rv < 0) {
Py_DECREF(v);
}
return rv;
}
#define insstr_modinit(d, name, value) \
do { \
if (insstr(d, name, value) < 0) \
goto error; \
} while(0)
static int
insint_worker(PyObject *d, PyObject *extra, char *name, long value)
{
PyObject *v = PyInt_FromLong(value);
if (v == NULL)
return -1;
if (insobj2(d, extra, name, v) < 0) {
Py_DECREF(v);
return -1;
}
return 0;
}
#define insint(d, name, value) \
do { \
if (insint_worker(d, NULL, name, value) < 0) \
goto error; \
} while(0)
#define insint_c(d, name, value) \
do { \
if (insint_worker(d, curlobject_constants, name, value) < 0) \
goto error; \
} while(0)
#define insint_m(d, name, value) \
do { \
if (insint_worker(d, curlmultiobject_constants, name, value) < 0) \
goto error; \
} while(0)
#define insint_s(d, name, value) \
do { \
if (insint_worker(d, curlshareobject_constants, name, value) < 0) \
goto error; \
} while(0)
#if PY_MAJOR_VERSION >= 3
/* Used in Python 3 only, and even then this function seems to never get
* called. Python 2 has no module cleanup:
* http://stackoverflow.com/questions/20741856/run-a-function-when-a-c-extension-module-is-freed-on-python-2
*/
static void do_curlmod_free(void *unused) {
PyMem_Free(g_pycurl_useragent);
g_pycurl_useragent = NULL;
}
static PyModuleDef curlmodule = {
PyModuleDef_HEAD_INIT,
"pycurl", /* m_name */
pycurl_module_doc, /* m_doc */
-1, /* m_size */
curl_methods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
do_curlmod_free /* m_free */
};
#endif
#if PY_MAJOR_VERSION >= 3
#define PYCURL_MODINIT_RETURN_NULL return NULL
PyMODINIT_FUNC PyInit_pycurl(void)
#else
#define PYCURL_MODINIT_RETURN_NULL return
/* Initialization function for the module */
#if defined(PyMODINIT_FUNC)
PyMODINIT_FUNC
#else
#if defined(__cplusplus)
extern "C"
#endif
DL_EXPORT(void)
#endif
initpycurl(void)
#endif
{
PyObject *m, *d;
const curl_version_info_data *vi;
const char *libcurl_version, *runtime_ssl_lib;
size_t libcurl_version_len, pycurl_version_len;
PyObject *xio_module = NULL;
PyObject *collections_module = NULL;
PyObject *named_tuple = NULL;
PyObject *arglist = NULL;
assert(Curl_Type.tp_weaklistoffset > 0);
assert(CurlMulti_Type.tp_weaklistoffset > 0);
assert(CurlShare_Type.tp_weaklistoffset > 0);
/* Check the version, as this has caused nasty problems in
* some cases. */
vi = curl_version_info(CURLVERSION_NOW);
if (vi == NULL) {
PyErr_SetString(PyExc_ImportError, "pycurl: curl_version_info() failed");
goto error;
}
if (vi->version_num < LIBCURL_VERSION_NUM) {
PyErr_Format(PyExc_ImportError, "pycurl: libcurl link-time version (%s) is older than compile-time version (%s)", vi->version, LIBCURL_VERSION);
goto error;
}
/* Our compiled crypto locks should correspond to runtime ssl library. */
if (vi->ssl_version == NULL) {
runtime_ssl_lib = "none/other";
} else if (!strncmp(vi->ssl_version, "OpenSSL/", 8) || !strncmp(vi->ssl_version, "LibreSSL/", 9) ||
!strncmp(vi->ssl_version, "BoringSSL", 9)) {
runtime_ssl_lib = "openssl";
} else if (!strncmp(vi->ssl_version, "GnuTLS/", 7)) {
runtime_ssl_lib = "gnutls";
} else if (!strncmp(vi->ssl_version, "NSS/", 4)) {
runtime_ssl_lib = "nss";
} else {
runtime_ssl_lib = "none/other";
}
if (strcmp(runtime_ssl_lib, COMPILE_SSL_LIB)) {
PyErr_Format(PyExc_ImportError, "pycurl: libcurl link-time ssl backend (%s) is different from compile-time ssl backend (%s)", runtime_ssl_lib, COMPILE_SSL_LIB);
goto error;
}
/* 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_CurlMulti_Type = &CurlMulti_Type;
p_CurlShare_Type = &CurlShare_Type;
Py_TYPE(&Curl_Type) = &PyType_Type;
Py_TYPE(&CurlMulti_Type) = &PyType_Type;
Py_TYPE(&CurlShare_Type) = &PyType_Type;
/* Create the module and add the functions */
if (PyType_Ready(&Curl_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)
goto error;
#else
/* returns a borrowed reference, XDECREFing it crashes the interpreter */
m = Py_InitModule3("pycurl", curl_methods, pycurl_module_doc);
if (m == NULL || !PyModule_Check(m))
goto error;
#endif
/* Add error object to the module */
d = PyModule_GetDict(m);
assert(d != NULL);
ErrorObject = PyErr_NewException("pycurl.error", NULL, NULL);
if (ErrorObject == NULL)
goto error;
if (PyDict_SetItemString(d, "error", ErrorObject) < 0) {
goto error;
}
curlobject_constants = PyDict_New();
if (curlobject_constants == NULL)
goto error;
curlmultiobject_constants = PyDict_New();
if (curlmultiobject_constants == NULL)
goto error;
curlshareobject_constants = PyDict_New();
if (curlshareobject_constants == NULL)
goto error;
/* Add version strings to the module */
libcurl_version = curl_version();
libcurl_version_len = strlen(libcurl_version);
#define PYCURL_VERSION_PREFIX_SIZE sizeof(PYCURL_VERSION_PREFIX)
/* PYCURL_VERSION_PREFIX_SIZE includes terminating null which will be
* replaced with the space; libcurl_version_len does not include
* terminating null. */
pycurl_version_len = PYCURL_VERSION_PREFIX_SIZE + libcurl_version_len + 1;
g_pycurl_useragent = PyMem_New(char, pycurl_version_len);
if (g_pycurl_useragent == NULL)
goto error;
memcpy(g_pycurl_useragent, PYCURL_VERSION_PREFIX, PYCURL_VERSION_PREFIX_SIZE);
g_pycurl_useragent[PYCURL_VERSION_PREFIX_SIZE-1] = ' ';
memcpy(g_pycurl_useragent + PYCURL_VERSION_PREFIX_SIZE,
libcurl_version, libcurl_version_len);
g_pycurl_useragent[pycurl_version_len - 1] = 0;
#undef PYCURL_VERSION_PREFIX_SIZE
insstr_modinit(d, "version", g_pycurl_useragent);
insint(d, "COMPILE_PY_VERSION_HEX", PY_VERSION_HEX);
insint(d, "COMPILE_LIBCURL_VERSION_NUM", LIBCURL_VERSION_NUM);
/* Types */
insobj2_modinit(d, NULL, "Curl", (PyObject *) p_Curl_Type);
insobj2_modinit(d, NULL, "CurlMulti", (PyObject *) p_CurlMulti_Type);
insobj2_modinit(d, NULL, "CurlShare", (PyObject *) p_CurlShare_Type);
/**
** the order of these constants mostly follows
**/
/* Abort curl_read_callback(). */
insint_c(d, "READFUNC_ABORT", CURL_READFUNC_ABORT);
insint_c(d, "READFUNC_PAUSE", CURL_READFUNC_PAUSE);
/* Pause curl_write_callback(). */
insint_c(d, "WRITEFUNC_PAUSE", CURL_WRITEFUNC_PAUSE);
/* constants for ioctl callback return values */
insint_c(d, "IOE_OK", CURLIOE_OK);
insint_c(d, "IOE_UNKNOWNCMD", CURLIOE_UNKNOWNCMD);
insint_c(d, "IOE_FAILRESTART", CURLIOE_FAILRESTART);
/* constants for ioctl callback argument values */
insint_c(d, "IOCMD_NOP", CURLIOCMD_NOP);
insint_c(d, "IOCMD_RESTARTREAD", CURLIOCMD_RESTARTREAD);
/* opensocketfunction return value */
insint_c(d, "SOCKET_BAD", CURL_SOCKET_BAD);
/* curl_infotype: the kind of data that is passed to information_callback */
/* XXX do we actually need curl_infotype in pycurl ??? */
insint_c(d, "INFOTYPE_TEXT", CURLINFO_TEXT);
insint_c(d, "INFOTYPE_HEADER_IN", CURLINFO_HEADER_IN);
insint_c(d, "INFOTYPE_HEADER_OUT", CURLINFO_HEADER_OUT);
insint_c(d, "INFOTYPE_DATA_IN", CURLINFO_DATA_IN);
insint_c(d, "INFOTYPE_DATA_OUT", CURLINFO_DATA_OUT);
insint_c(d, "INFOTYPE_SSL_DATA_IN", CURLINFO_SSL_DATA_IN);
insint_c(d, "INFOTYPE_SSL_DATA_OUT", CURLINFO_SSL_DATA_OUT);
/* CURLcode: error codes */
insint_c(d, "E_OK", CURLE_OK);
insint_c(d, "E_AGAIN", CURLE_AGAIN);
insint_c(d, "E_ALREADY_COMPLETE", CURLE_ALREADY_COMPLETE);
insint_c(d, "E_BAD_CALLING_ORDER", CURLE_BAD_CALLING_ORDER);
insint_c(d, "E_BAD_PASSWORD_ENTERED", CURLE_BAD_PASSWORD_ENTERED);
insint_c(d, "E_FTP_BAD_DOWNLOAD_RESUME", CURLE_FTP_BAD_DOWNLOAD_RESUME);
insint_c(d, "E_FTP_COULDNT_SET_TYPE", CURLE_FTP_COULDNT_SET_TYPE);
insint_c(d, "E_FTP_PARTIAL_FILE", CURLE_FTP_PARTIAL_FILE);
insint_c(d, "E_FTP_USER_PASSWORD_INCORRECT", CURLE_FTP_USER_PASSWORD_INCORRECT);
insint_c(d, "E_HTTP_NOT_FOUND", CURLE_HTTP_NOT_FOUND);
insint_c(d, "E_HTTP_PORT_FAILED", CURLE_HTTP_PORT_FAILED);
insint_c(d, "E_MALFORMAT_USER", CURLE_MALFORMAT_USER);
insint_c(d, "E_QUOTE_ERROR", CURLE_QUOTE_ERROR);
insint_c(d, "E_RANGE_ERROR", CURLE_RANGE_ERROR);
insint_c(d, "E_REMOTE_ACCESS_DENIED", CURLE_REMOTE_ACCESS_DENIED);
insint_c(d, "E_REMOTE_DISK_FULL", CURLE_REMOTE_DISK_FULL);
insint_c(d, "E_REMOTE_FILE_EXISTS", CURLE_REMOTE_FILE_EXISTS);
insint_c(d, "E_UPLOAD_FAILED", CURLE_UPLOAD_FAILED);
insint_c(d, "E_URL_MALFORMAT_USER", CURLE_URL_MALFORMAT_USER);
insint_c(d, "E_USE_SSL_FAILED", CURLE_USE_SSL_FAILED);
insint_c(d, "E_UNSUPPORTED_PROTOCOL", CURLE_UNSUPPORTED_PROTOCOL);
insint_c(d, "E_FAILED_INIT", CURLE_FAILED_INIT);
insint_c(d, "E_URL_MALFORMAT", CURLE_URL_MALFORMAT);
#ifdef HAVE_CURL_7_21_5
insint_c(d, "E_NOT_BUILT_IN", CURLE_NOT_BUILT_IN);
#endif
insint_c(d, "E_COULDNT_RESOLVE_PROXY", CURLE_COULDNT_RESOLVE_PROXY);
insint_c(d, "E_COULDNT_RESOLVE_HOST", CURLE_COULDNT_RESOLVE_HOST);
insint_c(d, "E_COULDNT_CONNECT", CURLE_COULDNT_CONNECT);
insint_c(d, "E_FTP_WEIRD_SERVER_REPLY", CURLE_FTP_WEIRD_SERVER_REPLY);
insint_c(d, "E_FTP_ACCESS_DENIED", CURLE_FTP_ACCESS_DENIED);
#ifdef HAVE_CURL_7_24_0
insint_c(d, "E_FTP_ACCEPT_FAILED", CURLE_FTP_ACCEPT_FAILED);
#endif
insint_c(d, "E_FTP_WEIRD_PASS_REPLY", CURLE_FTP_WEIRD_PASS_REPLY);
insint_c(d, "E_FTP_WEIRD_USER_REPLY", CURLE_FTP_WEIRD_USER_REPLY);
insint_c(d, "E_FTP_WEIRD_PASV_REPLY", CURLE_FTP_WEIRD_PASV_REPLY);
insint_c(d, "E_FTP_WEIRD_227_FORMAT", CURLE_FTP_WEIRD_227_FORMAT);
insint_c(d, "E_FTP_CANT_GET_HOST", CURLE_FTP_CANT_GET_HOST);
insint_c(d, "E_FTP_CANT_RECONNECT", CURLE_FTP_CANT_RECONNECT);
insint_c(d, "E_FTP_COULDNT_SET_BINARY", CURLE_FTP_COULDNT_SET_BINARY);
insint_c(d, "E_PARTIAL_FILE", CURLE_PARTIAL_FILE);
insint_c(d, "E_FTP_COULDNT_RETR_FILE", CURLE_FTP_COULDNT_RETR_FILE);
insint_c(d, "E_FTP_WRITE_ERROR", CURLE_FTP_WRITE_ERROR);
insint_c(d, "E_FTP_QUOTE_ERROR", CURLE_FTP_QUOTE_ERROR);
insint_c(d, "E_HTTP_RETURNED_ERROR", CURLE_HTTP_RETURNED_ERROR);
insint_c(d, "E_WRITE_ERROR", CURLE_WRITE_ERROR);
insint_c(d, "E_FTP_COULDNT_STOR_FILE", CURLE_FTP_COULDNT_STOR_FILE);
insint_c(d, "E_READ_ERROR", CURLE_READ_ERROR);
insint_c(d, "E_OUT_OF_MEMORY", CURLE_OUT_OF_MEMORY);
insint_c(d, "E_OPERATION_TIMEOUTED", CURLE_OPERATION_TIMEOUTED);
insint_c(d, "E_OPERATION_TIMEDOUT", CURLE_OPERATION_TIMEDOUT);
insint_c(d, "E_FTP_COULDNT_SET_ASCII", CURLE_FTP_COULDNT_SET_ASCII);
insint_c(d, "E_FTP_PORT_FAILED", CURLE_FTP_PORT_FAILED);
insint_c(d, "E_FTP_COULDNT_USE_REST", CURLE_FTP_COULDNT_USE_REST);
insint_c(d, "E_FTP_COULDNT_GET_SIZE", CURLE_FTP_COULDNT_GET_SIZE);
insint_c(d, "E_HTTP_RANGE_ERROR", CURLE_HTTP_RANGE_ERROR);
insint_c(d, "E_HTTP_POST_ERROR", CURLE_HTTP_POST_ERROR);
insint_c(d, "E_SSL_CACERT", CURLE_SSL_CACERT);
insint_c(d, "E_SSL_CACERT_BADFILE", CURLE_SSL_CACERT_BADFILE);
insint_c(d, "E_SSL_CERTPROBLEM", CURLE_SSL_CERTPROBLEM);
insint_c(d, "E_SSL_CIPHER", CURLE_SSL_CIPHER);
insint_c(d, "E_SSL_CONNECT_ERROR", CURLE_SSL_CONNECT_ERROR);
insint_c(d, "E_SSL_CRL_BADFILE", CURLE_SSL_CRL_BADFILE);
insint_c(d, "E_SSL_ENGINE_INITFAILED", CURLE_SSL_ENGINE_INITFAILED);
insint_c(d, "E_SSL_ENGINE_NOTFOUND", CURLE_SSL_ENGINE_NOTFOUND);
insint_c(d, "E_SSL_ENGINE_SETFAILED", CURLE_SSL_ENGINE_SETFAILED);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 41, 0)
insint_c(d, "E_SSL_INVALIDCERTSTATUS", CURLE_SSL_INVALIDCERTSTATUS);
#endif
insint_c(d, "E_SSL_ISSUER_ERROR", CURLE_SSL_ISSUER_ERROR);
insint_c(d, "E_SSL_PEER_CERTIFICATE", CURLE_SSL_PEER_CERTIFICATE);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 39, 0)
insint_c(d, "E_SSL_PINNEDPUBKEYNOTMATCH", CURLE_SSL_PINNEDPUBKEYNOTMATCH);
#endif
insint_c(d, "E_SSL_SHUTDOWN_FAILED", CURLE_SSL_SHUTDOWN_FAILED);
insint_c(d, "E_BAD_DOWNLOAD_RESUME", CURLE_BAD_DOWNLOAD_RESUME);
insint_c(d, "E_FILE_COULDNT_READ_FILE", CURLE_FILE_COULDNT_READ_FILE);
insint_c(d, "E_LDAP_CANNOT_BIND", CURLE_LDAP_CANNOT_BIND);
insint_c(d, "E_LDAP_SEARCH_FAILED", CURLE_LDAP_SEARCH_FAILED);
insint_c(d, "E_LIBRARY_NOT_FOUND", CURLE_LIBRARY_NOT_FOUND);
insint_c(d, "E_FUNCTION_NOT_FOUND", CURLE_FUNCTION_NOT_FOUND);
insint_c(d, "E_ABORTED_BY_CALLBACK", CURLE_ABORTED_BY_CALLBACK);
insint_c(d, "E_BAD_FUNCTION_ARGUMENT", CURLE_BAD_FUNCTION_ARGUMENT);
insint_c(d, "E_INTERFACE_FAILED", CURLE_INTERFACE_FAILED);
insint_c(d, "E_TOO_MANY_REDIRECTS", CURLE_TOO_MANY_REDIRECTS);
#ifdef HAVE_CURL_7_21_5
insint_c(d, "E_UNKNOWN_OPTION", CURLE_UNKNOWN_OPTION);
#endif
/* same as E_UNKNOWN_OPTION */
insint_c(d, "E_UNKNOWN_TELNET_OPTION", CURLE_UNKNOWN_TELNET_OPTION);
insint_c(d, "E_TELNET_OPTION_SYNTAX", CURLE_TELNET_OPTION_SYNTAX);
insint_c(d, "E_GOT_NOTHING", CURLE_GOT_NOTHING);
insint_c(d, "E_SEND_ERROR", CURLE_SEND_ERROR);
insint_c(d, "E_RECV_ERROR", CURLE_RECV_ERROR);
insint_c(d, "E_SHARE_IN_USE", CURLE_SHARE_IN_USE);
insint_c(d, "E_BAD_CONTENT_ENCODING", CURLE_BAD_CONTENT_ENCODING);
insint_c(d, "E_LDAP_INVALID_URL", CURLE_LDAP_INVALID_URL);
insint_c(d, "E_FILESIZE_EXCEEDED", CURLE_FILESIZE_EXCEEDED);
insint_c(d, "E_FTP_SSL_FAILED", CURLE_FTP_SSL_FAILED);
insint_c(d, "E_SEND_FAIL_REWIND", CURLE_SEND_FAIL_REWIND);
insint_c(d, "E_LOGIN_DENIED", CURLE_LOGIN_DENIED);
insint_c(d, "E_PEER_FAILED_VERIFICATION", CURLE_PEER_FAILED_VERIFICATION);
insint_c(d, "E_TFTP_NOTFOUND", CURLE_TFTP_NOTFOUND);
insint_c(d, "E_TFTP_PERM", CURLE_TFTP_PERM);
insint_c(d, "E_TFTP_DISKFULL", CURLE_TFTP_DISKFULL);
insint_c(d, "E_TFTP_ILLEGAL", CURLE_TFTP_ILLEGAL);
insint_c(d, "E_TFTP_UNKNOWNID", CURLE_TFTP_UNKNOWNID);
insint_c(d, "E_TFTP_EXISTS", CURLE_TFTP_EXISTS);
insint_c(d, "E_TFTP_NOSUCHUSER", CURLE_TFTP_NOSUCHUSER);
insint_c(d, "E_CONV_FAILED", CURLE_CONV_FAILED);
insint_c(d, "E_CONV_REQD", CURLE_CONV_REQD);
insint_c(d, "E_REMOTE_FILE_NOT_FOUND", CURLE_REMOTE_FILE_NOT_FOUND);
insint_c(d, "E_SSH", CURLE_SSH);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
insint_c(d, "E_FTP_PRET_FAILED", CURLE_FTP_PRET_FAILED);
insint_c(d, "E_RTSP_CSEQ_ERROR", CURLE_RTSP_CSEQ_ERROR);
insint_c(d, "E_RTSP_SESSION_ERROR", CURLE_RTSP_SESSION_ERROR);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 0)
insint_c(d, "E_CHUNK_FAILED", CURLE_CHUNK_FAILED);
insint_c(d, "E_FTP_BAD_FILE_LIST", CURLE_FTP_BAD_FILE_LIST);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 24, 0)
insint_c(d, "E_FTP_ACCEPT_TIMEOUT", CURLE_FTP_ACCEPT_TIMEOUT);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 30, 0)
insint_c(d, "E_NO_CONNECTION_AVAILABLE", CURLE_NO_CONNECTION_AVAILABLE);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 38, 0)
insint_c(d, "E_HTTP2", CURLE_HTTP2);
#endif
/* curl_proxytype: constants for setopt(PROXYTYPE, x) */
insint_c(d, "PROXYTYPE_HTTP", CURLPROXY_HTTP);
#ifdef HAVE_CURL_7_19_4_OPTS
insint_c(d, "PROXYTYPE_HTTP_1_0", CURLPROXY_HTTP_1_0);
#endif
insint_c(d, "PROXYTYPE_SOCKS4", CURLPROXY_SOCKS4);
insint_c(d, "PROXYTYPE_SOCKS4A", CURLPROXY_SOCKS4A);
insint_c(d, "PROXYTYPE_SOCKS5", CURLPROXY_SOCKS5);
insint_c(d, "PROXYTYPE_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5_HOSTNAME);
/* curl_httpauth: constants for setopt(HTTPAUTH, x) */
insint_c(d, "HTTPAUTH_ANY", CURLAUTH_ANY);
insint_c(d, "HTTPAUTH_ANYSAFE", CURLAUTH_ANYSAFE);
insint_c(d, "HTTPAUTH_BASIC", CURLAUTH_BASIC);
insint_c(d, "HTTPAUTH_DIGEST", CURLAUTH_DIGEST);
#ifdef HAVE_CURLAUTH_DIGEST_IE
insint_c(d, "HTTPAUTH_DIGEST_IE", CURLAUTH_DIGEST_IE);
#endif
insint_c(d, "HTTPAUTH_GSSNEGOTIATE", CURLAUTH_GSSNEGOTIATE);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 38, 0)
insint_c(d, "HTTPAUTH_NEGOTIATE", CURLAUTH_NEGOTIATE);
#endif
insint_c(d, "HTTPAUTH_NTLM", CURLAUTH_NTLM);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 22, 0)
insint_c(d, "HTTPAUTH_NTLM_WB", CURLAUTH_NTLM_WB);
#endif
insint_c(d, "HTTPAUTH_NONE", CURLAUTH_NONE);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 3)
insint_c(d, "HTTPAUTH_ONLY", CURLAUTH_ONLY);
#endif
#ifdef HAVE_CURL_7_22_0_OPTS
insint_c(d, "GSSAPI_DELEGATION_FLAG", CURLGSSAPI_DELEGATION_FLAG);
insint_c(d, "GSSAPI_DELEGATION_NONE", CURLGSSAPI_DELEGATION_NONE);
insint_c(d, "GSSAPI_DELEGATION_POLICY_FLAG", CURLGSSAPI_DELEGATION_POLICY_FLAG);
insint_c(d, "GSSAPI_DELEGATION", CURLOPT_GSSAPI_DELEGATION);
#endif
/* curl_ftpssl: constants for setopt(FTP_SSL, x) */
insint_c(d, "FTPSSL_NONE", CURLFTPSSL_NONE);
insint_c(d, "FTPSSL_TRY", CURLFTPSSL_TRY);
insint_c(d, "FTPSSL_CONTROL", CURLFTPSSL_CONTROL);
insint_c(d, "FTPSSL_ALL", CURLFTPSSL_ALL);
/* curl_ftpauth: constants for setopt(FTPSSLAUTH, x) */
insint_c(d, "FTPAUTH_DEFAULT", CURLFTPAUTH_DEFAULT);
insint_c(d, "FTPAUTH_SSL", CURLFTPAUTH_SSL);
insint_c(d, "FTPAUTH_TLS", CURLFTPAUTH_TLS);
/* curl_ftpauth: constants for setopt(FTPSSLAUTH, x) */
insint_c(d, "FORM_BUFFER", CURLFORM_BUFFER);
insint_c(d, "FORM_BUFFERPTR", CURLFORM_BUFFERPTR);
insint_c(d, "FORM_CONTENTS", CURLFORM_COPYCONTENTS);
insint_c(d, "FORM_FILE", CURLFORM_FILE);
insint_c(d, "FORM_CONTENTTYPE", CURLFORM_CONTENTTYPE);
insint_c(d, "FORM_FILENAME", CURLFORM_FILENAME);
/* FTP_FILEMETHOD options */
insint_c(d, "FTPMETHOD_DEFAULT", CURLFTPMETHOD_DEFAULT);
insint_c(d, "FTPMETHOD_MULTICWD", CURLFTPMETHOD_MULTICWD);
insint_c(d, "FTPMETHOD_NOCWD", CURLFTPMETHOD_NOCWD);
insint_c(d, "FTPMETHOD_SINGLECWD", CURLFTPMETHOD_SINGLECWD);
/* CURLoption: symbolic constants for setopt() */
insint_c(d, "APPEND", CURLOPT_APPEND);
insint_c(d, "COOKIESESSION", CURLOPT_COOKIESESSION);
insint_c(d, "DIRLISTONLY", CURLOPT_DIRLISTONLY);
/* ERRORBUFFER is not supported */
insint_c(d, "FILE", CURLOPT_WRITEDATA);
insint_c(d, "FTPPORT", CURLOPT_FTPPORT);
insint_c(d, "INFILE", CURLOPT_READDATA);
insint_c(d, "INFILESIZE", CURLOPT_INFILESIZE_LARGE); /* _LARGE ! */
insint_c(d, "KEYPASSWD", CURLOPT_KEYPASSWD);
insint_c(d, "LOW_SPEED_LIMIT", CURLOPT_LOW_SPEED_LIMIT);
insint_c(d, "LOW_SPEED_TIME", CURLOPT_LOW_SPEED_TIME);
insint_c(d, "PORT", CURLOPT_PORT);
insint_c(d, "POSTFIELDS", CURLOPT_POSTFIELDS);
insint_c(d, "PROXY", CURLOPT_PROXY);
#ifdef HAVE_CURLOPT_PROXYUSERNAME
insint_c(d, "PROXYPASSWORD", CURLOPT_PROXYPASSWORD);
insint_c(d, "PROXYUSERNAME", CURLOPT_PROXYUSERNAME);
#endif
insint_c(d, "PROXYUSERPWD", CURLOPT_PROXYUSERPWD);
insint_c(d, "RANGE", CURLOPT_RANGE);
insint_c(d, "READFUNCTION", CURLOPT_READFUNCTION);
insint_c(d, "REFERER", CURLOPT_REFERER);
insint_c(d, "RESUME_FROM", CURLOPT_RESUME_FROM_LARGE); /* _LARGE ! */
insint_c(d, "TELNETOPTIONS", CURLOPT_TELNETOPTIONS);
insint_c(d, "TIMEOUT", CURLOPT_TIMEOUT);
insint_c(d, "URL", CURLOPT_URL);
insint_c(d, "USE_SSL", CURLOPT_USE_SSL);
insint_c(d, "USERAGENT", CURLOPT_USERAGENT);
insint_c(d, "USERPWD", CURLOPT_USERPWD);
insint_c(d, "WRITEFUNCTION", CURLOPT_WRITEFUNCTION);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
insint_c(d, "OPT_RTSP_CLIENT_CSEQ", CURLOPT_RTSP_CLIENT_CSEQ);
insint_c(d, "OPT_RTSP_REQUEST", CURLOPT_RTSP_REQUEST);
insint_c(d, "OPT_RTSP_SERVER_CSEQ", CURLOPT_RTSP_SERVER_CSEQ);
insint_c(d, "OPT_RTSP_SESSION_ID", CURLOPT_RTSP_SESSION_ID);
insint_c(d, "OPT_RTSP_STREAM_URI", CURLOPT_RTSP_STREAM_URI);
insint_c(d, "OPT_RTSP_TRANSPORT", CURLOPT_RTSP_TRANSPORT);
#endif
#ifdef HAVE_CURLOPT_USERNAME
insint_c(d, "USERNAME", CURLOPT_USERNAME);
insint_c(d, "PASSWORD", CURLOPT_PASSWORD);
#endif
insint_c(d, "WRITEDATA", CURLOPT_WRITEDATA);
insint_c(d, "READDATA", CURLOPT_READDATA);
insint_c(d, "PROXYPORT", CURLOPT_PROXYPORT);
insint_c(d, "HTTPPROXYTUNNEL", CURLOPT_HTTPPROXYTUNNEL);
insint_c(d, "VERBOSE", CURLOPT_VERBOSE);
insint_c(d, "HEADER", CURLOPT_HEADER);
insint_c(d, "NOPROGRESS", CURLOPT_NOPROGRESS);
insint_c(d, "NOBODY", CURLOPT_NOBODY);
insint_c(d, "FAILONERROR", CURLOPT_FAILONERROR);
insint_c(d, "UPLOAD", CURLOPT_UPLOAD);
insint_c(d, "POST", CURLOPT_POST);
insint_c(d, "FTPLISTONLY", CURLOPT_FTPLISTONLY);
insint_c(d, "FTPAPPEND", CURLOPT_FTPAPPEND);
insint_c(d, "NETRC", CURLOPT_NETRC);
insint_c(d, "FOLLOWLOCATION", CURLOPT_FOLLOWLOCATION);
insint_c(d, "TRANSFERTEXT", CURLOPT_TRANSFERTEXT);
insint_c(d, "PUT", CURLOPT_PUT);
insint_c(d, "POSTFIELDSIZE", CURLOPT_POSTFIELDSIZE_LARGE); /* _LARGE ! */
insint_c(d, "COOKIE", CURLOPT_COOKIE);
insint_c(d, "HTTPHEADER", CURLOPT_HTTPHEADER);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
insint_c(d, "PROXYHEADER", CURLOPT_PROXYHEADER);
insint_c(d, "HEADEROPT", CURLOPT_HEADEROPT);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
insint_c(d, "PATH_AS_IS", CURLOPT_PATH_AS_IS);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
insint_c(d, "PIPEWAIT", CURLOPT_PIPEWAIT);
#endif
insint_c(d, "HTTPPOST", CURLOPT_HTTPPOST);
insint_c(d, "SSLCERT", CURLOPT_SSLCERT);
insint_c(d, "SSLCERTPASSWD", CURLOPT_SSLCERTPASSWD);
insint_c(d, "CRLF", CURLOPT_CRLF);
insint_c(d, "QUOTE", CURLOPT_QUOTE);
insint_c(d, "POSTQUOTE", CURLOPT_POSTQUOTE);
insint_c(d, "PREQUOTE", CURLOPT_PREQUOTE);
insint_c(d, "WRITEHEADER", CURLOPT_WRITEHEADER);
insint_c(d, "HEADERFUNCTION", CURLOPT_HEADERFUNCTION);
insint_c(d, "SEEKFUNCTION", CURLOPT_SEEKFUNCTION);
insint_c(d, "COOKIEFILE", CURLOPT_COOKIEFILE);
insint_c(d, "SSLVERSION", CURLOPT_SSLVERSION);
insint_c(d, "TIMECONDITION", CURLOPT_TIMECONDITION);
insint_c(d, "TIMEVALUE", CURLOPT_TIMEVALUE);
insint_c(d, "CUSTOMREQUEST", CURLOPT_CUSTOMREQUEST);
insint_c(d, "STDERR", CURLOPT_STDERR);
insint_c(d, "INTERFACE", CURLOPT_INTERFACE);
insint_c(d, "KRB4LEVEL", CURLOPT_KRB4LEVEL);
insint_c(d, "KRBLEVEL", CURLOPT_KRBLEVEL);
insint_c(d, "PROGRESSFUNCTION", CURLOPT_PROGRESSFUNCTION);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
insint_c(d, "XFERINFOFUNCTION", CURLOPT_XFERINFOFUNCTION);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
insint_c(d, "FTP_USE_PRET", CURLOPT_FTP_USE_PRET);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
insint_c(d, "LOGIN_OPTIONS", CURLOPT_LOGIN_OPTIONS);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 31, 0)
insint_c(d, "SASL_IR", CURLOPT_SASL_IR);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
insint_c(d, "XOAUTH2_BEARER", CURLOPT_XOAUTH2_BEARER);
#endif
insint_c(d, "SSL_VERIFYPEER", CURLOPT_SSL_VERIFYPEER);
insint_c(d, "CAPATH", CURLOPT_CAPATH);
insint_c(d, "CAINFO", CURLOPT_CAINFO);
insint_c(d, "OPT_FILETIME", CURLOPT_FILETIME);
insint_c(d, "MAXREDIRS", CURLOPT_MAXREDIRS);
insint_c(d, "MAXCONNECTS", CURLOPT_MAXCONNECTS);
insint_c(d, "FRESH_CONNECT", CURLOPT_FRESH_CONNECT);
insint_c(d, "FORBID_REUSE", CURLOPT_FORBID_REUSE);
insint_c(d, "RANDOM_FILE", CURLOPT_RANDOM_FILE);
insint_c(d, "EGDSOCKET", CURLOPT_EGDSOCKET);
insint_c(d, "CONNECTTIMEOUT", CURLOPT_CONNECTTIMEOUT);
insint_c(d, "HTTPGET", CURLOPT_HTTPGET);
insint_c(d, "SSL_VERIFYHOST", CURLOPT_SSL_VERIFYHOST);
insint_c(d, "COOKIEJAR", CURLOPT_COOKIEJAR);
insint_c(d, "SSL_CIPHER_LIST", CURLOPT_SSL_CIPHER_LIST);
insint_c(d, "HTTP_VERSION", CURLOPT_HTTP_VERSION);
insint_c(d, "FTP_USE_EPSV", CURLOPT_FTP_USE_EPSV);
insint_c(d, "SSLCERTTYPE", CURLOPT_SSLCERTTYPE);
insint_c(d, "SSLKEY", CURLOPT_SSLKEY);
insint_c(d, "SSLKEYTYPE", CURLOPT_SSLKEYTYPE);
/* same as CURLOPT_KEYPASSWD */
insint_c(d, "SSLKEYPASSWD", CURLOPT_SSLKEYPASSWD);
insint_c(d, "SSLENGINE", CURLOPT_SSLENGINE);
insint_c(d, "SSLENGINE_DEFAULT", CURLOPT_SSLENGINE_DEFAULT);
insint_c(d, "DNS_CACHE_TIMEOUT", CURLOPT_DNS_CACHE_TIMEOUT);
insint_c(d, "DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE);
insint_c(d, "DEBUGFUNCTION", CURLOPT_DEBUGFUNCTION);
insint_c(d, "BUFFERSIZE", CURLOPT_BUFFERSIZE);
insint_c(d, "NOSIGNAL", CURLOPT_NOSIGNAL);
insint_c(d, "SHARE", CURLOPT_SHARE);
insint_c(d, "PROXYTYPE", CURLOPT_PROXYTYPE);
/* superseded by ACCEPT_ENCODING */
insint_c(d, "ENCODING", CURLOPT_ENCODING);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 6)
insint_c(d, "ACCEPT_ENCODING", CURLOPT_ACCEPT_ENCODING);
insint_c(d, "TRANSFER_ENCODING", CURLOPT_TRANSFER_ENCODING);
#endif
insint_c(d, "HTTP200ALIASES", CURLOPT_HTTP200ALIASES);
insint_c(d, "UNRESTRICTED_AUTH", CURLOPT_UNRESTRICTED_AUTH);
insint_c(d, "FTP_USE_EPRT", CURLOPT_FTP_USE_EPRT);
insint_c(d, "HTTPAUTH", CURLOPT_HTTPAUTH);
insint_c(d, "FTP_CREATE_MISSING_DIRS", CURLOPT_FTP_CREATE_MISSING_DIRS);
insint_c(d, "PROXYAUTH", CURLOPT_PROXYAUTH);
insint_c(d, "FTP_RESPONSE_TIMEOUT", CURLOPT_FTP_RESPONSE_TIMEOUT);
insint_c(d, "IPRESOLVE", CURLOPT_IPRESOLVE);
insint_c(d, "MAXFILESIZE", CURLOPT_MAXFILESIZE_LARGE); /* _LARGE ! */
insint_c(d, "INFILESIZE_LARGE", CURLOPT_INFILESIZE_LARGE);
insint_c(d, "RESUME_FROM_LARGE", CURLOPT_RESUME_FROM_LARGE);
insint_c(d, "MAXFILESIZE_LARGE", CURLOPT_MAXFILESIZE_LARGE);
insint_c(d, "NETRC_FILE", CURLOPT_NETRC_FILE);
insint_c(d, "FTP_SSL", CURLOPT_FTP_SSL);
insint_c(d, "POSTFIELDSIZE_LARGE", CURLOPT_POSTFIELDSIZE_LARGE);
insint_c(d, "TCP_NODELAY", CURLOPT_TCP_NODELAY);
insint_c(d, "FTPSSLAUTH", CURLOPT_FTPSSLAUTH);
insint_c(d, "IOCTLFUNCTION", CURLOPT_IOCTLFUNCTION);
insint_c(d, "OPENSOCKETFUNCTION", CURLOPT_OPENSOCKETFUNCTION);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
insint_c(d, "CLOSESOCKETFUNCTION", CURLOPT_CLOSESOCKETFUNCTION);
#endif
insint_c(d, "SOCKOPTFUNCTION", CURLOPT_SOCKOPTFUNCTION);
insint_c(d, "FTP_ACCOUNT", CURLOPT_FTP_ACCOUNT);
insint_c(d, "IGNORE_CONTENT_LENGTH", CURLOPT_IGNORE_CONTENT_LENGTH);
insint_c(d, "COOKIELIST", CURLOPT_COOKIELIST);
insint_c(d, "OPT_COOKIELIST", CURLOPT_COOKIELIST);
insint_c(d, "FTP_SKIP_PASV_IP", CURLOPT_FTP_SKIP_PASV_IP);
insint_c(d, "FTP_FILEMETHOD", CURLOPT_FTP_FILEMETHOD);
insint_c(d, "CONNECT_ONLY", CURLOPT_CONNECT_ONLY);
insint_c(d, "LOCALPORT", CURLOPT_LOCALPORT);
insint_c(d, "LOCALPORTRANGE", CURLOPT_LOCALPORTRANGE);
insint_c(d, "FTP_ALTERNATIVE_TO_USER", CURLOPT_FTP_ALTERNATIVE_TO_USER);
insint_c(d, "MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE);
insint_c(d, "MAX_RECV_SPEED_LARGE", CURLOPT_MAX_RECV_SPEED_LARGE);
insint_c(d, "SSL_SESSIONID_CACHE", CURLOPT_SSL_SESSIONID_CACHE);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 41, 0)
insint_c(d, "SSL_VERIFYSTATUS", CURLOPT_SSL_VERIFYSTATUS);
#endif
insint_c(d, "SSH_AUTH_TYPES", CURLOPT_SSH_AUTH_TYPES);
insint_c(d, "SSH_PUBLIC_KEYFILE", CURLOPT_SSH_PUBLIC_KEYFILE);
insint_c(d, "SSH_PRIVATE_KEYFILE", CURLOPT_SSH_PRIVATE_KEYFILE);
#ifdef HAVE_CURL_7_19_6_OPTS
insint_c(d, "SSH_KNOWNHOSTS", CURLOPT_SSH_KNOWNHOSTS);
insint_c(d, "SSH_KEYFUNCTION", CURLOPT_SSH_KEYFUNCTION);
#endif
insint_c(d, "FTP_SSL_CCC", CURLOPT_FTP_SSL_CCC);
insint_c(d, "TIMEOUT_MS", CURLOPT_TIMEOUT_MS);
insint_c(d, "CONNECTTIMEOUT_MS", CURLOPT_CONNECTTIMEOUT_MS);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 24, 0)
insint_c(d, "ACCEPTTIMEOUT_MS", CURLOPT_ACCEPTTIMEOUT_MS);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 36, 0)
insint_c(d, "EXPECT_100_TIMEOUT_MS", CURLOPT_EXPECT_100_TIMEOUT_MS);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 25, 0)
insint_c(d, "TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE);
insint_c(d, "TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE);
insint_c(d, "TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL);
#endif
insint_c(d, "HTTP_TRANSFER_DECODING", CURLOPT_HTTP_TRANSFER_DECODING);
insint_c(d, "HTTP_CONTENT_DECODING", CURLOPT_HTTP_CONTENT_DECODING);
insint_c(d, "NEW_FILE_PERMS", CURLOPT_NEW_FILE_PERMS);
insint_c(d, "NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS);
insint_c(d, "POST301", CURLOPT_POST301);
insint_c(d, "PROXY_TRANSFER_MODE", CURLOPT_PROXY_TRANSFER_MODE);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
insint_c(d, "SERVICE_NAME", CURLOPT_SERVICE_NAME);
insint_c(d, "PROXY_SERVICE_NAME", CURLOPT_PROXY_SERVICE_NAME);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
insint_c(d, "PROXY_CAPATH", CURLOPT_PROXY_CAPATH);
insint_c(d, "PROXY_CAINFO", CURLOPT_PROXY_CAINFO);
insint_c(d, "PRE_PROXY", CURLOPT_PRE_PROXY);
insint_c(d, "PROXY_SSLCERT", CURLOPT_PROXY_SSLCERT);
insint_c(d, "PROXY_SSLCERTTYPE", CURLOPT_PROXY_SSLCERTTYPE);
insint_c(d, "PROXY_SSLKEY", CURLOPT_PROXY_SSLKEY);
insint_c(d, "PROXY_SSLKEYTYPE", CURLOPT_PROXY_SSLKEYTYPE);
insint_c(d, "PROXY_SSL_VERIFYPEER", CURLOPT_PROXY_SSL_VERIFYPEER);
#endif
insint_c(d, "COPYPOSTFIELDS", CURLOPT_COPYPOSTFIELDS);
insint_c(d, "SSH_HOST_PUBLIC_KEY_MD5", CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
insint_c(d, "AUTOREFERER", CURLOPT_AUTOREFERER);
insint_c(d, "CRLFILE", CURLOPT_CRLFILE);
insint_c(d, "ISSUERCERT", CURLOPT_ISSUERCERT);
insint_c(d, "ADDRESS_SCOPE", CURLOPT_ADDRESS_SCOPE);
#ifdef HAVE_CURLOPT_RESOLVE
insint_c(d, "RESOLVE", CURLOPT_RESOLVE);
#endif
#ifdef HAVE_CURLOPT_CERTINFO
insint_c(d, "OPT_CERTINFO", CURLOPT_CERTINFO);
#endif
#ifdef HAVE_CURLOPT_POSTREDIR
insint_c(d, "POSTREDIR", CURLOPT_POSTREDIR);
#endif
#ifdef HAVE_CURLOPT_NOPROXY
insint_c(d, "NOPROXY", CURLOPT_NOPROXY);
#endif
#ifdef HAVE_CURLOPT_PROTOCOLS
insint_c(d, "PROTOCOLS", CURLOPT_PROTOCOLS);
insint_c(d, "REDIR_PROTOCOLS", CURLOPT_REDIR_PROTOCOLS);
insint_c(d, "PROTO_HTTP", CURLPROTO_HTTP);
insint_c(d, "PROTO_HTTPS", CURLPROTO_HTTPS);
insint_c(d, "PROTO_FTP", CURLPROTO_FTP);
insint_c(d, "PROTO_FTPS", CURLPROTO_FTPS);
insint_c(d, "PROTO_SCP", CURLPROTO_SCP);
insint_c(d, "PROTO_SFTP", CURLPROTO_SFTP);
insint_c(d, "PROTO_TELNET", CURLPROTO_TELNET);
insint_c(d, "PROTO_LDAP", CURLPROTO_LDAP);
insint_c(d, "PROTO_LDAPS", CURLPROTO_LDAPS);
insint_c(d, "PROTO_DICT", CURLPROTO_DICT);
insint_c(d, "PROTO_FILE", CURLPROTO_FILE);
insint_c(d, "PROTO_TFTP", CURLPROTO_TFTP);
#ifdef HAVE_CURL_7_20_0_OPTS
insint_c(d, "PROTO_IMAP", CURLPROTO_IMAP);
insint_c(d, "PROTO_IMAPS", CURLPROTO_IMAPS);
insint_c(d, "PROTO_POP3", CURLPROTO_POP3);
insint_c(d, "PROTO_POP3S", CURLPROTO_POP3S);
insint_c(d, "PROTO_SMTP", CURLPROTO_SMTP);
insint_c(d, "PROTO_SMTPS", CURLPROTO_SMTPS);
#endif
#ifdef HAVE_CURL_7_21_0_OPTS
insint_c(d, "PROTO_RTSP", CURLPROTO_RTSP);
insint_c(d, "PROTO_RTMP", CURLPROTO_RTMP);
insint_c(d, "PROTO_RTMPT", CURLPROTO_RTMPT);
insint_c(d, "PROTO_RTMPE", CURLPROTO_RTMPE);
insint_c(d, "PROTO_RTMPTE", CURLPROTO_RTMPTE);
insint_c(d, "PROTO_RTMPS", CURLPROTO_RTMPS);
insint_c(d, "PROTO_RTMPTS", CURLPROTO_RTMPTS);
#endif
#ifdef HAVE_CURL_7_21_2_OPTS
insint_c(d, "PROTO_GOPHER", CURLPROTO_GOPHER);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 40, 0)
insint_c(d, "PROTO_SMB", CURLPROTO_SMB);
insint_c(d, "PROTO_SMBS", CURLPROTO_SMBS);
#endif
insint_c(d, "PROTO_ALL", CURLPROTO_ALL);
#endif
#ifdef HAVE_CURL_7_19_4_OPTS
insint_c(d, "TFTP_BLKSIZE", CURLOPT_TFTP_BLKSIZE);
insint_c(d, "SOCKS5_GSSAPI_SERVICE", CURLOPT_SOCKS5_GSSAPI_SERVICE);
insint_c(d, "SOCKS5_GSSAPI_NEC", CURLOPT_SOCKS5_GSSAPI_NEC);
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
insint_c(d, "MAIL_FROM", CURLOPT_MAIL_FROM);
insint_c(d, "MAIL_RCPT", CURLOPT_MAIL_RCPT);
#endif
#ifdef HAVE_CURL_7_25_0_OPTS
insint_c(d, "MAIL_AUTH", CURLOPT_MAIL_AUTH);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 39, 0)
insint_c(d, "PINNEDPUBLICKEY", CURLOPT_PINNEDPUBLICKEY);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 0)
insint_c(d, "WILDCARDMATCH", CURLOPT_WILDCARDMATCH);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 40, 0)
insint_c(d, "UNIX_SOCKET_PATH", CURLOPT_UNIX_SOCKET_PATH);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 36, 0)
insint_c(d, "SSL_ENABLE_ALPN", CURLOPT_SSL_ENABLE_ALPN);
insint_c(d, "SSL_ENABLE_NPN", CURLOPT_SSL_ENABLE_NPN);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 42, 0)
insint_c(d, "SSL_FALSESTART", CURLOPT_SSL_FALSESTART);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 25, 0)
insint_c(d, "SSL_OPTIONS", CURLOPT_SSL_OPTIONS);
insint_c(d, "SSLOPT_ALLOW_BEAST", CURLSSLOPT_ALLOW_BEAST);
# if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 44, 0)
insint_c(d, "SSLOPT_NO_REVOKE", CURLSSLOPT_NO_REVOKE);
# endif
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 4)
insint_c(d, "TLSAUTH_TYPE", CURLOPT_TLSAUTH_TYPE);
insint_c(d, "TLSAUTH_USERNAME", CURLOPT_TLSAUTH_USERNAME);
insint_c(d, "TLSAUTH_PASSWORD", CURLOPT_TLSAUTH_PASSWORD);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 45, 0)
insint_c(d, "DEFAULT_PROTOCOL", CURLOPT_DEFAULT_PROTOCOL);
#endif
insint_m(d, "M_TIMERFUNCTION", CURLMOPT_TIMERFUNCTION);
insint_m(d, "M_SOCKETFUNCTION", CURLMOPT_SOCKETFUNCTION);
insint_m(d, "M_PIPELINING", CURLMOPT_PIPELINING);
insint_m(d, "M_MAXCONNECTS", CURLMOPT_MAXCONNECTS);
#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
insint_m(d, "M_MAX_HOST_CONNECTIONS", CURLMOPT_MAX_HOST_CONNECTIONS);
insint_m(d, "M_MAX_TOTAL_CONNECTIONS", CURLMOPT_MAX_TOTAL_CONNECTIONS);
insint_m(d, "M_MAX_PIPELINE_LENGTH", CURLMOPT_MAX_PIPELINE_LENGTH);
insint_m(d, "M_CONTENT_LENGTH_PENALTY_SIZE", CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE);
insint_m(d, "M_CHUNK_LENGTH_PENALTY_SIZE", CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE);
insint_m(d, "M_PIPELINING_SITE_BL", CURLMOPT_PIPELINING_SITE_BL);
insint_m(d, "M_PIPELINING_SERVER_BL", CURLMOPT_PIPELINING_SERVER_BL);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
insint_m(d, "PIPE_NOTHING", CURLPIPE_NOTHING);
insint_m(d, "PIPE_HTTP1", CURLPIPE_HTTP1);
insint_m(d, "PIPE_MULTIPLEX", CURLPIPE_MULTIPLEX);
#endif
/* constants for setopt(IPRESOLVE, x) */
insint_c(d, "IPRESOLVE_WHATEVER", CURL_IPRESOLVE_WHATEVER);
insint_c(d, "IPRESOLVE_V4", CURL_IPRESOLVE_V4);
insint_c(d, "IPRESOLVE_V6", CURL_IPRESOLVE_V6);
/* constants for setopt(HTTP_VERSION, x) */
insint_c(d, "CURL_HTTP_VERSION_NONE", CURL_HTTP_VERSION_NONE);
insint_c(d, "CURL_HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0);
insint_c(d, "CURL_HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
insint_c(d, "CURL_HTTP_VERSION_2_0", CURL_HTTP_VERSION_2_0);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
insint_c(d, "CURL_HTTP_VERSION_2", CURL_HTTP_VERSION_2);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 47, 0)
insint_c(d, "CURL_HTTP_VERSION_2TLS", CURL_HTTP_VERSION_2TLS);
#endif
insint_c(d, "CURL_HTTP_VERSION_LAST", CURL_HTTP_VERSION_LAST);
/* CURL_NETRC_OPTION: constants for setopt(NETRC, x) */
insint_c(d, "NETRC_OPTIONAL", CURL_NETRC_OPTIONAL);
insint_c(d, "NETRC_IGNORED", CURL_NETRC_IGNORED);
insint_c(d, "NETRC_REQUIRED", CURL_NETRC_REQUIRED);
/* constants for setopt(SSLVERSION, x) */
insint_c(d, "SSLVERSION_DEFAULT", CURL_SSLVERSION_DEFAULT);
insint_c(d, "SSLVERSION_SSLv2", CURL_SSLVERSION_SSLv2);
insint_c(d, "SSLVERSION_SSLv3", CURL_SSLVERSION_SSLv3);
insint_c(d, "SSLVERSION_TLSv1", CURL_SSLVERSION_TLSv1);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
insint_c(d, "SSLVERSION_TLSv1_0", CURL_SSLVERSION_TLSv1_0);
insint_c(d, "SSLVERSION_TLSv1_1", CURL_SSLVERSION_TLSv1_1);
insint_c(d, "SSLVERSION_TLSv1_2", CURL_SSLVERSION_TLSv1_2);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
insint_c(d, "SSLVERSION_TLSv1_3", CURL_SSLVERSION_TLSv1_3);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 54, 0)
insint_c(d, "SSLVERSION_MAX_DEFAULT", CURL_SSLVERSION_MAX_DEFAULT);
insint_c(d, "SSLVERSION_MAX_TLSv1_0", CURL_SSLVERSION_MAX_TLSv1_0);
insint_c(d, "SSLVERSION_MAX_TLSv1_1", CURL_SSLVERSION_MAX_TLSv1_1);
insint_c(d, "SSLVERSION_MAX_TLSv1_2", CURL_SSLVERSION_MAX_TLSv1_2);
insint_c(d, "SSLVERSION_MAX_TLSv1_3", CURL_SSLVERSION_MAX_TLSv1_3);
#endif
/* curl_TimeCond: constants for setopt(TIMECONDITION, x) */
insint_c(d, "TIMECONDITION_NONE", CURL_TIMECOND_NONE);
insint_c(d, "TIMECONDITION_IFMODSINCE", CURL_TIMECOND_IFMODSINCE);
insint_c(d, "TIMECONDITION_IFUNMODSINCE", CURL_TIMECOND_IFUNMODSINCE);
insint_c(d, "TIMECONDITION_LASTMOD", CURL_TIMECOND_LASTMOD);
/* constants for setopt(CURLOPT_SSH_AUTH_TYPES, x) */
insint_c(d, "SSH_AUTH_ANY", CURLSSH_AUTH_ANY);
insint_c(d, "SSH_AUTH_NONE", CURLSSH_AUTH_NONE);
insint_c(d, "SSH_AUTH_PUBLICKEY", CURLSSH_AUTH_PUBLICKEY);
insint_c(d, "SSH_AUTH_PASSWORD", CURLSSH_AUTH_PASSWORD);
insint_c(d, "SSH_AUTH_HOST", CURLSSH_AUTH_HOST);
insint_c(d, "SSH_AUTH_KEYBOARD", CURLSSH_AUTH_KEYBOARD);
insint_c(d, "SSH_AUTH_DEFAULT", CURLSSH_AUTH_DEFAULT);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 28, 0)
insint_c(d, "SSH_AUTH_AGENT", CURLSSH_AUTH_AGENT);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
insint_c(d, "HEADER_UNIFIED", CURLHEADER_UNIFIED);
insint_c(d, "HEADER_SEPARATE", CURLHEADER_SEPARATE);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 5)
insint_c(d, "SOCKOPT_ALREADY_CONNECTED", CURL_SOCKOPT_ALREADY_CONNECTED);
insint_c(d, "SOCKOPT_ERROR", CURL_SOCKOPT_ERROR);
insint_c(d, "SOCKOPT_OK", CURL_SOCKOPT_OK);
#endif
#ifdef HAVE_CURL_7_19_6_OPTS
/* curl_khtype constants */
insint_c(d, "KHTYPE_UNKNOWN", CURLKHTYPE_UNKNOWN);
insint_c(d, "KHTYPE_RSA1", CURLKHTYPE_RSA1);
insint_c(d, "KHTYPE_RSA", CURLKHTYPE_RSA);
insint_c(d, "KHTYPE_DSS", CURLKHTYPE_DSS);
/* curl_khmatch constants, passed to sshkeycallback */
insint_c(d, "KHMATCH_OK", CURLKHMATCH_OK);
insint_c(d, "KHMATCH_MISMATCH", CURLKHMATCH_MISMATCH);
insint_c(d, "KHMATCH_MISSING", CURLKHMATCH_MISSING);
/* return values for CURLOPT_SSH_KEYFUNCTION */
insint_c(d, "KHSTAT_FINE_ADD_TO_FILE", CURLKHSTAT_FINE_ADD_TO_FILE);
insint_c(d, "KHSTAT_FINE", CURLKHSTAT_FINE);
insint_c(d, "KHSTAT_REJECT", CURLKHSTAT_REJECT);
insint_c(d, "KHSTAT_DEFER", CURLKHSTAT_DEFER);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 28, 0)
insint_c(d, "SOCKTYPE_ACCEPT", CURLSOCKTYPE_ACCEPT);
#endif
insint_c(d, "SOCKTYPE_IPCXN", CURLSOCKTYPE_IPCXN);
insint_c(d, "USESSL_NONE", CURLUSESSL_NONE);
insint_c(d, "USESSL_TRY", CURLUSESSL_TRY);
insint_c(d, "USESSL_CONTROL", CURLUSESSL_CONTROL);
insint_c(d, "USESSL_ALL", CURLUSESSL_ALL);
/* CURLINFO: symbolic constants for getinfo(x) */
insint_c(d, "EFFECTIVE_URL", CURLINFO_EFFECTIVE_URL);
/* same as CURLINFO_RESPONSE_CODE */
insint_c(d, "HTTP_CODE", CURLINFO_HTTP_CODE);
insint_c(d, "RESPONSE_CODE", CURLINFO_RESPONSE_CODE);
insint_c(d, "TOTAL_TIME", CURLINFO_TOTAL_TIME);
insint_c(d, "NAMELOOKUP_TIME", CURLINFO_NAMELOOKUP_TIME);
insint_c(d, "CONNECT_TIME", CURLINFO_CONNECT_TIME);
insint_c(d, "APPCONNECT_TIME", CURLINFO_APPCONNECT_TIME);
insint_c(d, "PRETRANSFER_TIME", CURLINFO_PRETRANSFER_TIME);
insint_c(d, "SIZE_UPLOAD", CURLINFO_SIZE_UPLOAD);
insint_c(d, "SIZE_DOWNLOAD", CURLINFO_SIZE_DOWNLOAD);
insint_c(d, "SPEED_DOWNLOAD", CURLINFO_SPEED_DOWNLOAD);
insint_c(d, "SPEED_UPLOAD", CURLINFO_SPEED_UPLOAD);
insint_c(d, "HEADER_SIZE", CURLINFO_HEADER_SIZE);
insint_c(d, "REQUEST_SIZE", CURLINFO_REQUEST_SIZE);
insint_c(d, "SSL_VERIFYRESULT", CURLINFO_SSL_VERIFYRESULT);
insint_c(d, "INFO_FILETIME", CURLINFO_FILETIME);
insint_c(d, "CONTENT_LENGTH_DOWNLOAD", CURLINFO_CONTENT_LENGTH_DOWNLOAD);
insint_c(d, "CONTENT_LENGTH_UPLOAD", CURLINFO_CONTENT_LENGTH_UPLOAD);
insint_c(d, "STARTTRANSFER_TIME", CURLINFO_STARTTRANSFER_TIME);
insint_c(d, "CONTENT_TYPE", CURLINFO_CONTENT_TYPE);
insint_c(d, "REDIRECT_TIME", CURLINFO_REDIRECT_TIME);
insint_c(d, "REDIRECT_COUNT", CURLINFO_REDIRECT_COUNT);
insint_c(d, "REDIRECT_URL", CURLINFO_REDIRECT_URL);
insint_c(d, "PRIMARY_IP", CURLINFO_PRIMARY_IP);
#ifdef HAVE_CURLINFO_PRIMARY_PORT
insint_c(d, "PRIMARY_PORT", CURLINFO_PRIMARY_PORT);
#endif
#ifdef HAVE_CURLINFO_LOCAL_IP
insint_c(d, "LOCAL_IP", CURLINFO_LOCAL_IP);
#endif
#ifdef HAVE_CURLINFO_LOCAL_PORT
insint_c(d, "LOCAL_PORT", CURLINFO_LOCAL_PORT);
#endif
insint_c(d, "HTTP_CONNECTCODE", CURLINFO_HTTP_CONNECTCODE);
insint_c(d, "HTTPAUTH_AVAIL", CURLINFO_HTTPAUTH_AVAIL);
insint_c(d, "PROXYAUTH_AVAIL", CURLINFO_PROXYAUTH_AVAIL);
insint_c(d, "OS_ERRNO", CURLINFO_OS_ERRNO);
insint_c(d, "NUM_CONNECTS", CURLINFO_NUM_CONNECTS);
insint_c(d, "SSL_ENGINES", CURLINFO_SSL_ENGINES);
insint_c(d, "INFO_COOKIELIST", CURLINFO_COOKIELIST);
insint_c(d, "LASTSOCKET", CURLINFO_LASTSOCKET);
insint_c(d, "FTP_ENTRY_PATH", CURLINFO_FTP_ENTRY_PATH);
#ifdef HAVE_CURLOPT_CERTINFO
insint_c(d, "INFO_CERTINFO", CURLINFO_CERTINFO);
#endif
#ifdef HAVE_CURL_7_19_4_OPTS
insint_c(d, "CONDITION_UNMET", CURLINFO_CONDITION_UNMET);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
insint_c(d, "INFO_RTSP_CLIENT_CSEQ", CURLINFO_RTSP_CLIENT_CSEQ);
insint_c(d, "INFO_RTSP_CSEQ_RECV", CURLINFO_RTSP_CSEQ_RECV);
insint_c(d, "INFO_RTSP_SERVER_CSEQ", CURLINFO_RTSP_SERVER_CSEQ);
insint_c(d, "INFO_RTSP_SESSION_ID", CURLINFO_RTSP_SESSION_ID);
insint_c(d, "RTSPREQ_NONE",CURL_RTSPREQ_NONE);
insint_c(d, "RTSPREQ_OPTIONS",CURL_RTSPREQ_OPTIONS);
insint_c(d, "RTSPREQ_DESCRIBE",CURL_RTSPREQ_DESCRIBE);
insint_c(d, "RTSPREQ_ANNOUNCE",CURL_RTSPREQ_ANNOUNCE);
insint_c(d, "RTSPREQ_SETUP",CURL_RTSPREQ_SETUP);
insint_c(d, "RTSPREQ_PLAY",CURL_RTSPREQ_PLAY);
insint_c(d, "RTSPREQ_PAUSE",CURL_RTSPREQ_PAUSE);
insint_c(d, "RTSPREQ_TEARDOWN",CURL_RTSPREQ_TEARDOWN);
insint_c(d, "RTSPREQ_GET_PARAMETER",CURL_RTSPREQ_GET_PARAMETER);
insint_c(d, "RTSPREQ_SET_PARAMETER",CURL_RTSPREQ_SET_PARAMETER);
insint_c(d, "RTSPREQ_RECORD",CURL_RTSPREQ_RECORD);
insint_c(d, "RTSPREQ_RECEIVE",CURL_RTSPREQ_RECEIVE);
insint_c(d, "RTSPREQ_LAST",CURL_RTSPREQ_LAST);
#endif
/* CURLPAUSE: symbolic constants for pause(bitmask) */
insint_c(d, "PAUSE_RECV", CURLPAUSE_RECV);
insint_c(d, "PAUSE_SEND", CURLPAUSE_SEND);
insint_c(d, "PAUSE_ALL", CURLPAUSE_ALL);
insint_c(d, "PAUSE_CONT", CURLPAUSE_CONT);
#ifdef HAVE_CURL_7_19_5_OPTS
/* CURL_SEEKFUNC: return values for seek function */
insint_c(d, "SEEKFUNC_OK", CURL_SEEKFUNC_OK);
insint_c(d, "SEEKFUNC_FAIL", CURL_SEEKFUNC_FAIL);
insint_c(d, "SEEKFUNC_CANTSEEK", CURL_SEEKFUNC_CANTSEEK);
#endif
#ifdef HAVE_CURLOPT_DNS_SERVERS
insint_c(d, "DNS_SERVERS", CURLOPT_DNS_SERVERS);
#endif
#ifdef HAVE_CURLOPT_POSTREDIR
insint_c(d, "REDIR_POST_301", CURL_REDIR_POST_301);
insint_c(d, "REDIR_POST_302", CURL_REDIR_POST_302);
# ifdef HAVE_CURL_REDIR_POST_303
insint_c(d, "REDIR_POST_303", CURL_REDIR_POST_303);
# endif
insint_c(d, "REDIR_POST_ALL", CURL_REDIR_POST_ALL);
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
insint_c(d, "CONNECT_TO", CURLOPT_CONNECT_TO);
#endif
#ifdef HAVE_CURLINFO_HTTP_VERSION
insint_c(d, "INFO_HTTP_VERSION", CURLINFO_HTTP_VERSION);
#endif
/* options for global_init() */
insint(d, "GLOBAL_SSL", CURL_GLOBAL_SSL);
insint(d, "GLOBAL_WIN32", CURL_GLOBAL_WIN32);
insint(d, "GLOBAL_ALL", CURL_GLOBAL_ALL);
insint(d, "GLOBAL_NOTHING", CURL_GLOBAL_NOTHING);
insint(d, "GLOBAL_DEFAULT", CURL_GLOBAL_DEFAULT);
#ifdef CURL_GLOBAL_ACK_EINTR
/* CURL_GLOBAL_ACK_EINTR was introduced in libcurl-7.30.0 */
insint(d, "GLOBAL_ACK_EINTR", CURL_GLOBAL_ACK_EINTR);
#endif
/* constants for curl_multi_socket interface */
insint(d, "CSELECT_IN", CURL_CSELECT_IN);
insint(d, "CSELECT_OUT", CURL_CSELECT_OUT);
insint(d, "CSELECT_ERR", CURL_CSELECT_ERR);
insint(d, "SOCKET_TIMEOUT", CURL_SOCKET_TIMEOUT);
insint(d, "POLL_NONE", CURL_POLL_NONE);
insint(d, "POLL_IN", CURL_POLL_IN);
insint(d, "POLL_OUT", CURL_POLL_OUT);
insint(d, "POLL_INOUT", CURL_POLL_INOUT);
insint(d, "POLL_REMOVE", CURL_POLL_REMOVE);
/* curl_lock_data: XXX do we need this in pycurl ??? */
/* curl_lock_access: XXX do we need this in pycurl ??? */
/* CURLSHcode: XXX do we need this in pycurl ??? */
/* CURLSHoption: XXX do we need this in pycurl ??? */
/* CURLversion: constants for curl_version_info(x) */
#if 0
/* XXX - do we need these ?? */
insint(d, "VERSION_FIRST", CURLVERSION_FIRST);
insint(d, "VERSION_SECOND", CURLVERSION_SECOND);
insint(d, "VERSION_THIRD", CURLVERSION_THIRD);
insint(d, "VERSION_NOW", CURLVERSION_NOW);
#endif
/* version features - bitmasks for curl_version_info_data.features */
insint(d, "VERSION_IPV6", CURL_VERSION_IPV6);
insint(d, "VERSION_KERBEROS4", CURL_VERSION_KERBEROS4);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 40, 0)
insint(d, "VERSION_KERBEROS5", CURL_VERSION_KERBEROS5);
#endif
insint(d, "VERSION_SSL", CURL_VERSION_SSL);
insint(d, "VERSION_LIBZ", CURL_VERSION_LIBZ);
insint(d, "VERSION_NTLM", CURL_VERSION_NTLM);
insint(d, "VERSION_GSSNEGOTIATE", CURL_VERSION_GSSNEGOTIATE);
insint(d, "VERSION_DEBUG", CURL_VERSION_DEBUG);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 6)
insint(d, "VERSION_CURLDEBUG", CURL_VERSION_CURLDEBUG);
#endif
insint(d, "VERSION_ASYNCHDNS", CURL_VERSION_ASYNCHDNS);
insint(d, "VERSION_SPNEGO", CURL_VERSION_SPNEGO);
insint(d, "VERSION_LARGEFILE", CURL_VERSION_LARGEFILE);
insint(d, "VERSION_IDN", CURL_VERSION_IDN);
insint(d, "VERSION_SSPI", CURL_VERSION_SSPI);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 38, 0)
insint(d, "VERSION_GSSAPI", CURL_VERSION_GSSAPI);
#endif
insint(d, "VERSION_CONV", CURL_VERSION_CONV);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 4)
insint(d, "VERSION_TLSAUTH_SRP", CURL_VERSION_TLSAUTH_SRP);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 22, 0)
insint(d, "VERSION_NTLM_WB", CURL_VERSION_NTLM_WB);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
insint(d, "VERSION_HTTP2", CURL_VERSION_HTTP2);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 40, 0)
insint(d, "VERSION_UNIX_SOCKETS", CURL_VERSION_UNIX_SOCKETS);
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 47, 0)
insint(d, "VERSION_PSL", CURL_VERSION_PSL);
#endif
/**
** the order of these constants mostly follows
**/
/* CURLMcode: multi error codes */
/* old symbol */
insint_m(d, "E_CALL_MULTI_PERFORM", CURLM_CALL_MULTI_PERFORM);
/* new symbol for consistency */
insint_m(d, "E_MULTI_CALL_MULTI_PERFORM", CURLM_CALL_MULTI_PERFORM);
insint_m(d, "E_MULTI_OK", CURLM_OK);
insint_m(d, "E_MULTI_BAD_HANDLE", CURLM_BAD_HANDLE);
insint_m(d, "E_MULTI_BAD_EASY_HANDLE", CURLM_BAD_EASY_HANDLE);
insint_m(d, "E_MULTI_BAD_SOCKET", CURLM_BAD_SOCKET);
insint_m(d, "E_MULTI_CALL_MULTI_SOCKET", CURLM_CALL_MULTI_SOCKET);
insint_m(d, "E_MULTI_OUT_OF_MEMORY", CURLM_OUT_OF_MEMORY);
insint_m(d, "E_MULTI_INTERNAL_ERROR", CURLM_INTERNAL_ERROR);
insint_m(d, "E_MULTI_UNKNOWN_OPTION", CURLM_UNKNOWN_OPTION);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 1)
insint_m(d, "E_MULTI_ADDED_ALREADY", CURLM_ADDED_ALREADY);
#endif
/* curl shared constants */
insint_s(d, "SH_SHARE", CURLSHOPT_SHARE);
insint_s(d, "SH_UNSHARE", CURLSHOPT_UNSHARE);
insint_s(d, "LOCK_DATA_COOKIE", CURL_LOCK_DATA_COOKIE);
insint_s(d, "LOCK_DATA_DNS", CURL_LOCK_DATA_DNS);
insint_s(d, "LOCK_DATA_SSL_SESSION", CURL_LOCK_DATA_SSL_SESSION);
/* Initialize callback locks if ssl is enabled */
#if defined(PYCURL_NEED_SSL_TSL)
if (pycurl_ssl_init() != 0) {
goto error;
}
#endif
#if PY_MAJOR_VERSION >= 3
xio_module = PyImport_ImportModule("io");
if (xio_module == NULL) {
goto error;
}
bytesio = PyObject_GetAttrString(xio_module, "BytesIO");
if (bytesio == NULL) {
goto error;
}
stringio = PyObject_GetAttrString(xio_module, "StringIO");
if (stringio == NULL) {
goto error;
}
#else
xio_module = PyImport_ImportModule("cStringIO");
if (xio_module == NULL) {
PyErr_Clear();
xio_module = PyImport_ImportModule("StringIO");
if (xio_module == NULL) {
goto error;
}
}
stringio = PyObject_GetAttrString(xio_module, "StringIO");
if (stringio == NULL) {
goto error;
}
bytesio = stringio;
Py_INCREF(bytesio);
#endif
collections_module = PyImport_ImportModule("collections");
if (collections_module == NULL) {
goto error;
}
named_tuple = PyObject_GetAttrString(collections_module, "namedtuple");
if (named_tuple == NULL) {
goto error;
}
#ifdef HAVE_CURL_7_19_6_OPTS
arglist = Py_BuildValue("ss", "KhKey", "key keytype");
if (arglist == NULL) {
goto error;
}
khkey_type = PyObject_Call(named_tuple, arglist, NULL);
if (khkey_type == NULL) {
goto error;
}
Py_DECREF(arglist);
PyDict_SetItemString(d, "KhKey", khkey_type);
#endif
arglist = Py_BuildValue("ss", "CurlSockAddr", "family socktype protocol addr");
if (arglist == NULL) {
goto error;
}
curl_sockaddr_type = PyObject_Call(named_tuple, arglist, NULL);
if (curl_sockaddr_type == NULL) {
goto error;
}
Py_DECREF(arglist);
PyDict_SetItemString(d, "CurlSockAddr", curl_sockaddr_type);
#ifdef WITH_THREAD
/* Finally initialize global interpreter lock */
PyEval_InitThreads();
#endif
#if PY_MAJOR_VERSION >= 3
return m;
#else
PYCURL_MODINIT_RETURN_NULL;
#endif
error:
Py_XDECREF(curlobject_constants);
Py_XDECREF(curlmultiobject_constants);
Py_XDECREF(curlshareobject_constants);
Py_XDECREF(ErrorObject);
Py_XDECREF(collections_module);
Py_XDECREF(named_tuple);
Py_XDECREF(xio_module);
Py_XDECREF(bytesio);
Py_XDECREF(stringio);
Py_XDECREF(arglist);
#ifdef HAVE_CURL_7_19_6_OPTS
Py_XDECREF(khkey_type);
Py_XDECREF(curl_sockaddr_type);
#endif
PyMem_Free(g_pycurl_useragent);
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ImportError, "curl module init failed");
PYCURL_MODINIT_RETURN_NULL;
}
pycurl-7.43.0.2/src/easyopt.c 0000644 0001750 0001750 00000111671 13301332107 014726 0 ustar me me 0000000 0000000 #include "pycurl.h"
static struct curl_slist *
pycurl_list_or_tuple_to_slist(int which, PyObject *obj, Py_ssize_t len)
{
struct curl_slist *slist = NULL;
Py_ssize_t i;
for (i = 0; i < len; i++) {
PyObject *listitem = PyListOrTuple_GetItem(obj, i, which);
struct curl_slist *nlist;
char *str;
PyObject *sencoded_obj;
if (!PyText_Check(listitem)) {
curl_slist_free_all(slist);
PyErr_SetString(PyExc_TypeError, "list items must be byte strings or Unicode strings with ASCII code points only");
return NULL;
}
/* INFO: curl_slist_append() internally does strdup() the data, so
* no embedded NUL characters allowed here. */
str = PyText_AsString_NoNUL(listitem, &sencoded_obj);
if (str == NULL) {
curl_slist_free_all(slist);
return NULL;
}
nlist = curl_slist_append(slist, str);
PyText_EncodedDecref(sencoded_obj);
if (nlist == NULL || nlist->data == NULL) {
curl_slist_free_all(slist);
PyErr_NoMemory();
return NULL;
}
slist = nlist;
}
return slist;
}
static PyObject *
util_curl_unsetopt(CurlObject *self, int option)
{
int res;
#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_CALLBACK(callback_option, data_option, callback_field) \
case callback_option: \
if ((res = curl_easy_setopt(self->handle, callback_option, NULL)) != CURLE_OK) \
goto error; \
if ((res = curl_easy_setopt(self->handle, data_option, NULL)) != CURLE_OK) \
goto error; \
Py_CLEAR(callback_field); \
break
/* FIXME: implement more options. Have to carefully check lib/url.c in the
* libcurl source code to see if it's actually safe to simply
* unset the option. */
switch (option)
{
case CURLOPT_SHARE:
SETOPT((CURLSH *) NULL);
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;
case CURLOPT_WRITEHEADER:
SETOPT((void *) 0);
Py_CLEAR(self->writeheader_fp);
break;
case CURLOPT_CAINFO:
case CURLOPT_CAPATH:
case CURLOPT_COOKIE:
case CURLOPT_COOKIEJAR:
case CURLOPT_CUSTOMREQUEST:
case CURLOPT_EGDSOCKET:
case CURLOPT_ENCODING:
case CURLOPT_FTPPORT:
case CURLOPT_PROXYUSERPWD:
#ifdef HAVE_CURLOPT_PROXYUSERNAME
case CURLOPT_PROXYUSERNAME:
case CURLOPT_PROXYPASSWORD:
#endif
case CURLOPT_RANDOM_FILE:
case CURLOPT_SSL_CIPHER_LIST:
case CURLOPT_USERPWD:
#ifdef HAVE_CURLOPT_USERNAME
case CURLOPT_USERNAME:
case CURLOPT_PASSWORD:
#endif
case CURLOPT_RANGE:
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
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:
case CURLOPT_PRE_PROXY:
case CURLOPT_PROXY_SSLCERT:
case CURLOPT_PROXY_SSLCERTTYPE:
case CURLOPT_PROXY_SSLKEY:
case CURLOPT_PROXY_SSLKEYTYPE:
#endif
SETOPT((char *) NULL);
break;
#ifdef HAVE_CURLOPT_CERTINFO
case CURLOPT_CERTINFO:
SETOPT((long) 0);
break;
#endif
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);
#endif
CLEAR_CALLBACK(CURLOPT_SOCKOPTFUNCTION, CURLOPT_SOCKOPTDATA, self->sockopt_cb);
#ifdef HAVE_CURL_7_19_6_OPTS
CLEAR_CALLBACK(CURLOPT_SSH_KEYFUNCTION, CURLOPT_SSH_KEYDATA, self->ssh_key_cb);
#endif
/* info: we explicitly list unsupported options here */
case CURLOPT_COOKIEFILE:
default:
PyErr_SetString(PyExc_TypeError, "unsetopt() is not supported for this option");
return NULL;
}
Py_RETURN_NONE;
error:
CURLERROR_RETVAL();
#undef SETOPT
#undef SETOPT2
#undef CLEAR_CALLBACK
}
PYCURL_INTERNAL PyObject *
do_curl_unsetopt(CurlObject *self, PyObject *args)
{
int option;
if (!PyArg_ParseTuple(args, "i:unsetopt", &option)) {
return NULL;
}
if (check_curl_state(self, 1 | 2, "unsetopt") != 0) {
return NULL;
}
/* early checks of option value */
if (option <= 0)
goto error;
if (option >= (int)CURLOPTTYPE_OFF_T + OPTIONS_SIZE)
goto error;
if (option % 10000 >= OPTIONS_SIZE)
goto error;
return util_curl_unsetopt(self, option);
error:
PyErr_SetString(PyExc_TypeError, "invalid arguments to unsetopt");
return NULL;
}
static PyObject *
do_curl_setopt_string_impl(CurlObject *self, int option, PyObject *obj)
{
char *str = NULL;
Py_ssize_t len = -1;
PyObject *encoded_obj;
int res;
/* Check that the option specified a string as well as the input */
switch (option) {
case CURLOPT_CAINFO:
case CURLOPT_CAPATH:
case CURLOPT_COOKIE:
case CURLOPT_COOKIEFILE:
case CURLOPT_COOKIELIST:
case CURLOPT_COOKIEJAR:
case CURLOPT_CUSTOMREQUEST:
case CURLOPT_EGDSOCKET:
/* use CURLOPT_ENCODING instead of CURLOPT_ACCEPT_ENCODING
for compatibility with older libcurls */
case CURLOPT_ENCODING:
case CURLOPT_FTPPORT:
case CURLOPT_INTERFACE:
case CURLOPT_KEYPASSWD:
case CURLOPT_NETRC_FILE:
case CURLOPT_PROXY:
case CURLOPT_PROXYUSERPWD:
#ifdef HAVE_CURLOPT_PROXYUSERNAME
case CURLOPT_PROXYUSERNAME:
case CURLOPT_PROXYPASSWORD:
#endif
case CURLOPT_RANDOM_FILE:
case CURLOPT_RANGE:
case CURLOPT_REFERER:
case CURLOPT_SSLCERT:
case CURLOPT_SSLCERTTYPE:
case CURLOPT_SSLENGINE:
case CURLOPT_SSLKEY:
case CURLOPT_SSLKEYTYPE:
case CURLOPT_SSL_CIPHER_LIST:
case CURLOPT_URL:
case CURLOPT_USERAGENT:
case CURLOPT_USERPWD:
#ifdef HAVE_CURLOPT_USERNAME
case CURLOPT_USERNAME:
case CURLOPT_PASSWORD:
#endif
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
case CURLOPT_SSH_PUBLIC_KEYFILE:
case CURLOPT_SSH_PRIVATE_KEYFILE:
case CURLOPT_COPYPOSTFIELDS:
case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
case CURLOPT_CRLFILE:
case CURLOPT_ISSUERCERT:
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
case CURLOPT_RTSP_STREAM_URI:
case CURLOPT_RTSP_SESSION_ID:
case CURLOPT_RTSP_TRANSPORT:
#endif
#ifdef HAVE_CURLOPT_DNS_SERVERS
case CURLOPT_DNS_SERVERS:
#endif
#ifdef HAVE_CURLOPT_NOPROXY
case CURLOPT_NOPROXY:
#endif
#ifdef HAVE_CURL_7_19_4_OPTS
case CURLOPT_SOCKS5_GSSAPI_SERVICE:
#endif
#ifdef HAVE_CURL_7_19_6_OPTS
case CURLOPT_SSH_KNOWNHOSTS:
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
case CURLOPT_MAIL_FROM:
#endif
#ifdef HAVE_CURL_7_25_0_OPTS
case CURLOPT_MAIL_AUTH:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 39, 0)
case CURLOPT_PINNEDPUBLICKEY:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 43, 0)
case CURLOPT_SERVICE_NAME:
case CURLOPT_PROXY_SERVICE_NAME:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 0)
case CURLOPT_WILDCARDMATCH:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 40, 0)
case CURLOPT_UNIX_SOCKET_PATH:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 4)
case CURLOPT_TLSAUTH_TYPE:
case CURLOPT_TLSAUTH_USERNAME:
case CURLOPT_TLSAUTH_PASSWORD:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 45, 0)
case CURLOPT_DEFAULT_PROTOCOL:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 34, 0)
case CURLOPT_LOGIN_OPTIONS:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 33, 0)
case CURLOPT_XOAUTH2_BEARER:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 52, 0)
case CURLOPT_PROXY_CAPATH:
case CURLOPT_PROXY_CAINFO:
case CURLOPT_PRE_PROXY:
case CURLOPT_PROXY_SSLCERT:
case CURLOPT_PROXY_SSLCERTTYPE:
case CURLOPT_PROXY_SSLKEY:
case CURLOPT_PROXY_SSLKEYTYPE:
#endif
case CURLOPT_KRBLEVEL:
str = PyText_AsString_NoNUL(obj, &encoded_obj);
if (str == NULL)
return NULL;
break;
case CURLOPT_POSTFIELDS:
if (PyText_AsStringAndSize(obj, &str, &len, &encoded_obj) != 0)
return NULL;
/* automatically set POSTFIELDSIZE */
if (len <= INT_MAX) {
res = curl_easy_setopt(self->handle, CURLOPT_POSTFIELDSIZE, (long)len);
} else {
res = curl_easy_setopt(self->handle, CURLOPT_POSTFIELDSIZE_LARGE, (curl_off_t)len);
}
if (res != CURLE_OK) {
PyText_EncodedDecref(encoded_obj);
CURLERROR_RETVAL();
}
break;
default:
PyErr_SetString(PyExc_TypeError, "strings are not supported for this option");
return NULL;
}
assert(str != NULL);
/* Call setopt */
res = curl_easy_setopt(self->handle, (CURLoption)option, str);
/* Check for errors */
if (res != CURLE_OK) {
PyText_EncodedDecref(encoded_obj);
CURLERROR_RETVAL();
}
/* libcurl does not copy the value of CURLOPT_POSTFIELDS */
if (option == CURLOPT_POSTFIELDS) {
PyObject *store_obj;
/* if obj was bytes, it was not encoded, and we need to incref obj.
* if obj was unicode, it was encoded, and we need to incref
* encoded_obj - except we can simply transfer ownership.
*/
if (encoded_obj) {
store_obj = encoded_obj;
} else {
/* no encoding is performed, incref the original object. */
store_obj = obj;
Py_INCREF(store_obj);
}
util_curl_xdecref(self, PYCURL_MEMGROUP_POSTFIELDS, self->handle);
self->postfields_obj = store_obj;
} else {
PyText_EncodedDecref(encoded_obj);
}
Py_RETURN_NONE;
}
#define IS_LONG_OPTION(o) (o < CURLOPTTYPE_OBJECTPOINT)
#define IS_OFF_T_OPTION(o) (o >= CURLOPTTYPE_OFF_T)
static PyObject *
do_curl_setopt_int(CurlObject *self, int option, PyObject *obj)
{
long d;
PY_LONG_LONG ld;
int res;
if (IS_LONG_OPTION(option)) {
d = PyInt_AsLong(obj);
res = curl_easy_setopt(self->handle, (CURLoption)option, (long)d);
} else if (IS_OFF_T_OPTION(option)) {
/* this path should only be taken in Python 3 */
ld = PyLong_AsLongLong(obj);
res = curl_easy_setopt(self->handle, (CURLoption)option, (curl_off_t)ld);
} else {
PyErr_SetString(PyExc_TypeError, "integers are not supported for this option");
return NULL;
}
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
Py_RETURN_NONE;
}
static PyObject *
do_curl_setopt_long(CurlObject *self, int option, PyObject *obj)
{
int res;
PY_LONG_LONG d = PyLong_AsLongLong(obj);
if (d == -1 && PyErr_Occurred())
return NULL;
if (IS_LONG_OPTION(option) && (long)d == d)
res = curl_easy_setopt(self->handle, (CURLoption)option, (long)d);
else if (IS_OFF_T_OPTION(option) && (curl_off_t)d == d)
res = curl_easy_setopt(self->handle, (CURLoption)option, (curl_off_t)d);
else {
PyErr_SetString(PyExc_TypeError, "longs are not supported for this option");
return NULL;
}
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
Py_RETURN_NONE;
}
#undef IS_LONG_OPTION
#undef IS_OFF_T_OPTION
#if PY_MAJOR_VERSION < 3 && !defined(PYCURL_AVOID_STDIO)
static PyObject *
do_curl_setopt_file_passthrough(CurlObject *self, int option, PyObject *obj)
{
FILE *fp;
int res;
fp = PyFile_AsFile(obj);
if (fp == NULL) {
PyErr_SetString(PyExc_TypeError, "second argument must be open file");
return NULL;
}
switch (option) {
case CURLOPT_READDATA:
res = curl_easy_setopt(self->handle, CURLOPT_READFUNCTION, fread);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
break;
case CURLOPT_WRITEDATA:
res = curl_easy_setopt(self->handle, CURLOPT_WRITEFUNCTION, fwrite);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
break;
case CURLOPT_WRITEHEADER:
res = curl_easy_setopt(self->handle, CURLOPT_HEADERFUNCTION, fwrite);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
break;
default:
PyErr_SetString(PyExc_TypeError, "files are not supported for this option");
return NULL;
}
res = curl_easy_setopt(self->handle, (CURLoption)option, fp);
if (res != CURLE_OK) {
/*
If we get here fread/fwrite are set as callbacks but the file pointer
is not set, program will crash if it does not reset read/write
callback. Also, we won't do the memory management later in this
function.
*/
CURLERROR_RETVAL();
}
Py_INCREF(obj);
switch (option) {
case CURLOPT_READDATA:
Py_CLEAR(self->readdata_fp);
self->readdata_fp = obj;
break;
case CURLOPT_WRITEDATA:
Py_CLEAR(self->writedata_fp);
self->writedata_fp = obj;
break;
case CURLOPT_WRITEHEADER:
Py_CLEAR(self->writeheader_fp);
self->writeheader_fp = obj;
break;
default:
assert(0);
break;
}
/* Return success */
Py_RETURN_NONE;
}
#endif
static PyObject *
do_curl_setopt_httppost(CurlObject *self, int option, int which, PyObject *obj)
{
struct curl_httppost *post = NULL;
struct curl_httppost *last = NULL;
/* List of all references that have been INCed as a result of
* this operation */
PyObject *ref_params = NULL;
PyObject *nencoded_obj, *cencoded_obj, *oencoded_obj;
int which_httppost_item, which_httppost_option;
PyObject *httppost_option;
Py_ssize_t i, len;
int res;
len = PyListOrTuple_Size(obj, which);
if (len == 0)
Py_RETURN_NONE;
for (i = 0; i < len; i++) {
char *nstr = NULL, *cstr = NULL;
Py_ssize_t nlen = -1, clen = -1;
PyObject *listitem = PyListOrTuple_GetItem(obj, i, which);
which_httppost_item = PyListOrTuple_Check(listitem);
if (!which_httppost_item) {
PyErr_SetString(PyExc_TypeError, "list items must be list or tuple objects");
goto error;
}
if (PyListOrTuple_Size(listitem, which_httppost_item) != 2) {
PyErr_SetString(PyExc_TypeError, "list or tuple must contain two elements (name, value)");
goto error;
}
if (PyText_AsStringAndSize(PyListOrTuple_GetItem(listitem, 0, which_httppost_item),
&nstr, &nlen, &nencoded_obj) != 0) {
PyErr_SetString(PyExc_TypeError, "list or tuple must contain a byte string or Unicode string with ASCII code points only as first element");
goto error;
}
httppost_option = PyListOrTuple_GetItem(listitem, 1, which_httppost_item);
if (PyText_Check(httppost_option)) {
/* Handle strings as second argument for backwards compatibility */
if (PyText_AsStringAndSize(httppost_option, &cstr, &clen, &cencoded_obj)) {
PyText_EncodedDecref(nencoded_obj);
CURLERROR_SET_RETVAL();
goto error;
}
/* INFO: curl_formadd() internally does memdup() the data, so
* embedded NUL characters _are_ allowed here. */
res = curl_formadd(&post, &last,
CURLFORM_COPYNAME, nstr,
CURLFORM_NAMELENGTH, (long) nlen,
CURLFORM_COPYCONTENTS, cstr,
CURLFORM_CONTENTSLENGTH, (long) clen,
CURLFORM_END);
PyText_EncodedDecref(cencoded_obj);
if (res != CURLE_OK) {
PyText_EncodedDecref(nencoded_obj);
CURLERROR_SET_RETVAL();
goto error;
}
}
/* assignment is intended */
else if ((which_httppost_option = PyListOrTuple_Check(httppost_option))) {
/* Supports content, file and content-type */
Py_ssize_t tlen = PyListOrTuple_Size(httppost_option, which_httppost_option);
int j, k, l;
struct curl_forms *forms = NULL;
/* Sanity check that there are at least two tuple items */
if (tlen < 2) {
PyText_EncodedDecref(nencoded_obj);
PyErr_SetString(PyExc_TypeError, "list or tuple must contain at least one option and one value");
goto error;
}
if (tlen % 2 == 1) {
PyText_EncodedDecref(nencoded_obj);
PyErr_SetString(PyExc_TypeError, "list or tuple must contain an even number of items");
goto error;
}
/* Allocate enough space to accommodate length options for content or buffers, plus a terminator. */
forms = PyMem_New(struct curl_forms, (tlen*2) + 1);
if (forms == NULL) {
PyText_EncodedDecref(nencoded_obj);
PyErr_NoMemory();
goto error;
}
/* Iterate all the tuple members pairwise */
for (j = 0, k = 0, l = 0; j < tlen; j += 2, l++) {
char *ostr;
Py_ssize_t olen;
int val;
if (j == (tlen-1)) {
PyErr_SetString(PyExc_TypeError, "expected value");
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
if (!PyInt_Check(PyListOrTuple_GetItem(httppost_option, j, which_httppost_option))) {
PyErr_SetString(PyExc_TypeError, "option must be an integer");
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
if (!PyText_Check(PyListOrTuple_GetItem(httppost_option, j+1, which_httppost_option))) {
PyErr_SetString(PyExc_TypeError, "value must be a byte string or a Unicode string with ASCII code points only");
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
val = PyLong_AsLong(PyListOrTuple_GetItem(httppost_option, j, which_httppost_option));
if (val != CURLFORM_COPYCONTENTS &&
val != CURLFORM_FILE &&
val != CURLFORM_FILENAME &&
val != CURLFORM_CONTENTTYPE &&
val != CURLFORM_BUFFER &&
val != CURLFORM_BUFFERPTR)
{
PyErr_SetString(PyExc_TypeError, "unsupported option");
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
if (PyText_AsStringAndSize(PyListOrTuple_GetItem(httppost_option, j+1, which_httppost_option), &ostr, &olen, &oencoded_obj)) {
/* exception should be already set */
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
forms[k].option = val;
forms[k].value = ostr;
++k;
if (val == CURLFORM_COPYCONTENTS) {
/* Contents can contain \0 bytes so we specify the length */
forms[k].option = CURLFORM_CONTENTSLENGTH;
forms[k].value = (const char *)olen;
++k;
} else if (val == CURLFORM_BUFFERPTR) {
PyObject *obj = NULL;
if (ref_params == NULL) {
ref_params = PyList_New((Py_ssize_t)0);
if (ref_params == NULL) {
PyText_EncodedDecref(oencoded_obj);
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
}
/* Keep a reference to the object that holds the ostr buffer. */
if (oencoded_obj == NULL) {
obj = PyListOrTuple_GetItem(httppost_option, j+1, which_httppost_option);
}
else {
obj = oencoded_obj;
}
/* Ensure that the buffer remains alive until curl_easy_cleanup() */
if (PyList_Append(ref_params, obj) != 0) {
PyText_EncodedDecref(oencoded_obj);
PyMem_Free(forms);
PyText_EncodedDecref(nencoded_obj);
goto error;
}
/* As with CURLFORM_COPYCONTENTS, specify the length. */
forms[k].option = CURLFORM_BUFFERLENGTH;
forms[k].value = (const char *)olen;
++k;
}
}
forms[k].option = CURLFORM_END;
res = curl_formadd(&post, &last,
CURLFORM_COPYNAME, nstr,
CURLFORM_NAMELENGTH, (long) nlen,
CURLFORM_ARRAY, forms,
CURLFORM_END);
PyText_EncodedDecref(oencoded_obj);
PyMem_Free(forms);
if (res != CURLE_OK) {
PyText_EncodedDecref(nencoded_obj);
CURLERROR_SET_RETVAL();
goto error;
}
} else {
/* Some other type was given, ignore */
PyText_EncodedDecref(nencoded_obj);
PyErr_SetString(PyExc_TypeError, "unsupported second type in tuple");
goto error;
}
PyText_EncodedDecref(nencoded_obj);
}
res = curl_easy_setopt(self->handle, CURLOPT_HTTPPOST, post);
/* Check for errors */
if (res != CURLE_OK) {
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;
Py_RETURN_NONE;
error:
curl_formfree(post);
Py_XDECREF(ref_params);
return NULL;
}
static PyObject *
do_curl_setopt_list(CurlObject *self, int option, int which, PyObject *obj)
{
struct curl_slist **old_slist = NULL;
struct curl_slist *slist = NULL;
Py_ssize_t len;
int res;
switch (option) {
case CURLOPT_HTTP200ALIASES:
old_slist = &self->http200aliases;
break;
case CURLOPT_HTTPHEADER:
old_slist = &self->httpheader;
break;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
case CURLOPT_PROXYHEADER:
old_slist = &self->proxyheader;
break;
#endif
case CURLOPT_POSTQUOTE:
old_slist = &self->postquote;
break;
case CURLOPT_PREQUOTE:
old_slist = &self->prequote;
break;
case CURLOPT_QUOTE:
old_slist = &self->quote;
break;
case CURLOPT_TELNETOPTIONS:
old_slist = &self->telnetoptions;
break;
#ifdef HAVE_CURLOPT_RESOLVE
case CURLOPT_RESOLVE:
old_slist = &self->resolve;
break;
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
case CURLOPT_MAIL_RCPT:
old_slist = &self->mail_rcpt;
break;
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
case CURLOPT_CONNECT_TO:
old_slist = &self->connect_to;
break;
#endif
default:
/* None of the list options were recognized, raise exception */
PyErr_SetString(PyExc_TypeError, "lists are not supported for this option");
return NULL;
}
len = PyListOrTuple_Size(obj, which);
if (len == 0)
Py_RETURN_NONE;
/* Just to be sure we do not bug off here */
assert(old_slist != NULL && slist == NULL);
/* Handle regular list operations on the other options */
slist = pycurl_list_or_tuple_to_slist(which, obj, len);
if (slist == NULL) {
return NULL;
}
res = curl_easy_setopt(self->handle, (CURLoption)option, slist);
/* Check for errors */
if (res != CURLE_OK) {
curl_slist_free_all(slist);
CURLERROR_RETVAL();
}
/* Finally, free previously allocated list and update */
curl_slist_free_all(*old_slist);
*old_slist = slist;
Py_RETURN_NONE;
}
static PyObject *
do_curl_setopt_callable(CurlObject *self, int option, PyObject *obj)
{
/* We use function types here to make sure that our callback
* definitions exactly match the interface.
*/
const curl_write_callback w_cb = write_callback;
const curl_write_callback h_cb = header_callback;
const curl_read_callback r_cb = read_callback;
const curl_progress_callback pro_cb = progress_callback;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
const curl_xferinfo_callback xferinfo_cb = xferinfo_callback;
#endif
const curl_debug_callback debug_cb = debug_callback;
const curl_ioctl_callback ioctl_cb = ioctl_callback;
const curl_opensocket_callback opensocket_cb = opensocket_callback;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
const curl_closesocket_callback closesocket_cb = closesocket_callback;
#endif
const curl_seek_callback seek_cb = seek_callback;
switch(option) {
case CURLOPT_WRITEFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->writedata_fp);
Py_CLEAR(self->w_cb);
self->w_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_WRITEFUNCTION, w_cb);
curl_easy_setopt(self->handle, CURLOPT_WRITEDATA, self);
break;
case CURLOPT_HEADERFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->writeheader_fp);
Py_CLEAR(self->h_cb);
self->h_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_HEADERFUNCTION, h_cb);
curl_easy_setopt(self->handle, CURLOPT_WRITEHEADER, self);
break;
case CURLOPT_READFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->readdata_fp);
Py_CLEAR(self->r_cb);
self->r_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_READFUNCTION, r_cb);
curl_easy_setopt(self->handle, CURLOPT_READDATA, self);
break;
case CURLOPT_PROGRESSFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->pro_cb);
self->pro_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_PROGRESSFUNCTION, pro_cb);
curl_easy_setopt(self->handle, CURLOPT_PROGRESSDATA, self);
break;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
case CURLOPT_XFERINFOFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->xferinfo_cb);
self->xferinfo_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_XFERINFOFUNCTION, xferinfo_cb);
curl_easy_setopt(self->handle, CURLOPT_XFERINFODATA, self);
break;
#endif
case CURLOPT_DEBUGFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->debug_cb);
self->debug_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_DEBUGFUNCTION, debug_cb);
curl_easy_setopt(self->handle, CURLOPT_DEBUGDATA, self);
break;
case CURLOPT_IOCTLFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->ioctl_cb);
self->ioctl_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_IOCTLFUNCTION, ioctl_cb);
curl_easy_setopt(self->handle, CURLOPT_IOCTLDATA, self);
break;
case CURLOPT_OPENSOCKETFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->opensocket_cb);
self->opensocket_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_cb);
curl_easy_setopt(self->handle, CURLOPT_OPENSOCKETDATA, self);
break;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
case CURLOPT_CLOSESOCKETFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->closesocket_cb);
self->closesocket_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_CLOSESOCKETFUNCTION, closesocket_cb);
curl_easy_setopt(self->handle, CURLOPT_CLOSESOCKETDATA, self);
break;
#endif
case CURLOPT_SOCKOPTFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->sockopt_cb);
self->sockopt_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_SOCKOPTFUNCTION, sockopt_cb);
curl_easy_setopt(self->handle, CURLOPT_SOCKOPTDATA, self);
break;
#ifdef HAVE_CURL_7_19_6_OPTS
case CURLOPT_SSH_KEYFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->ssh_key_cb);
self->ssh_key_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_SSH_KEYFUNCTION, ssh_key_cb);
curl_easy_setopt(self->handle, CURLOPT_SSH_KEYDATA, self);
break;
#endif
case CURLOPT_SEEKFUNCTION:
Py_INCREF(obj);
Py_CLEAR(self->seek_cb);
self->seek_cb = obj;
curl_easy_setopt(self->handle, CURLOPT_SEEKFUNCTION, seek_cb);
curl_easy_setopt(self->handle, CURLOPT_SEEKDATA, self);
break;
default:
/* None of the function options were recognized, raise exception */
PyErr_SetString(PyExc_TypeError, "functions are not supported for this option");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
do_curl_setopt_share(CurlObject *self, PyObject *obj)
{
CurlShareObject *share;
int res;
if (self->share == NULL && (obj == NULL || obj == Py_None))
Py_RETURN_NONE;
if (self->share) {
if (obj != Py_None) {
PyErr_SetString(ErrorObject, "Curl object already sharing. Unshare first.");
return NULL;
}
else {
share = self->share;
res = curl_easy_setopt(self->handle, CURLOPT_SHARE, NULL);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
self->share = NULL;
Py_DECREF(share);
Py_RETURN_NONE;
}
}
if (Py_TYPE(obj) != p_CurlShare_Type) {
PyErr_SetString(PyExc_TypeError, "invalid arguments to setopt");
return NULL;
}
share = (CurlShareObject*)obj;
res = curl_easy_setopt(self->handle, CURLOPT_SHARE, share->share_handle);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
self->share = share;
Py_INCREF(share);
Py_RETURN_NONE;
}
PYCURL_INTERNAL PyObject *
do_curl_setopt_filelike(CurlObject *self, int option, PyObject *obj)
{
const char *method_name;
PyObject *method;
if (option == CURLOPT_READDATA) {
method_name = "read";
} else {
method_name = "write";
}
method = PyObject_GetAttrString(obj, method_name);
if (method) {
PyObject *arglist;
PyObject *rv;
switch (option) {
case CURLOPT_READDATA:
option = CURLOPT_READFUNCTION;
break;
case CURLOPT_WRITEDATA:
option = CURLOPT_WRITEFUNCTION;
break;
case CURLOPT_WRITEHEADER:
option = CURLOPT_HEADERFUNCTION;
break;
default:
PyErr_SetString(PyExc_TypeError, "objects are not supported for this option");
Py_DECREF(method);
return NULL;
}
arglist = Py_BuildValue("(iO)", option, method);
/* reference is now in arglist */
Py_DECREF(method);
if (arglist == NULL) {
return NULL;
}
rv = do_curl_setopt(self, arglist);
Py_DECREF(arglist);
return rv;
} else {
if (option == CURLOPT_READDATA) {
PyErr_SetString(PyExc_TypeError, "object given without a read method");
} else {
PyErr_SetString(PyExc_TypeError, "object given without a write method");
}
return NULL;
}
}
PYCURL_INTERNAL PyObject *
do_curl_setopt(CurlObject *self, PyObject *args)
{
int option;
PyObject *obj;
int which;
if (!PyArg_ParseTuple(args, "iO:setopt", &option, &obj))
return NULL;
if (check_curl_state(self, 1 | 2, "setopt") != 0)
return NULL;
/* early checks of option value */
if (option <= 0)
goto error;
if (option >= (int)CURLOPTTYPE_OFF_T + OPTIONS_SIZE)
goto error;
if (option % 10000 >= OPTIONS_SIZE)
goto error;
/* Handle the case of None as the call of unsetopt() */
if (obj == Py_None) {
return util_curl_unsetopt(self, option);
}
/* Handle the case of string arguments */
if (PyText_Check(obj)) {
return do_curl_setopt_string_impl(self, option, obj);
}
/* Handle the case of integer arguments */
if (PyInt_Check(obj)) {
return do_curl_setopt_int(self, option, obj);
}
/* Handle the case of long arguments (used by *_LARGE options) */
if (PyLong_Check(obj)) {
return do_curl_setopt_long(self, option, obj);
}
#if PY_MAJOR_VERSION < 3 && !defined(PYCURL_AVOID_STDIO)
/* Handle the case of file objects */
if (PyFile_Check(obj)) {
return do_curl_setopt_file_passthrough(self, option, obj);
}
#endif
/* Handle the case of list or tuple objects */
which = PyListOrTuple_Check(obj);
if (which) {
if (option == CURLOPT_HTTPPOST) {
return do_curl_setopt_httppost(self, option, which, obj);
} else {
return do_curl_setopt_list(self, option, which, obj);
}
}
/* Handle the case of function objects for callbacks */
if (PyFunction_Check(obj) || PyCFunction_Check(obj) ||
PyCallable_Check(obj) || PyMethod_Check(obj)) {
return do_curl_setopt_callable(self, option, obj);
}
/* handle the SHARE case */
if (option == CURLOPT_SHARE) {
return do_curl_setopt_share(self, obj);
}
/*
Handle the case of file-like objects.
Given an object with a write method, we will call the write method
from the appropriate callback.
Files in Python 3 are no longer FILE * instances and therefore cannot
be directly given to curl, therefore this method handles all I/O to
Python objects.
In Python 2 true file objects are FILE * instances and will be handled
by stdio passthrough code invoked above, and file-like objects will
be handled by this method.
*/
if (option == CURLOPT_READDATA ||
option == CURLOPT_WRITEDATA ||
option == CURLOPT_WRITEHEADER)
{
return do_curl_setopt_filelike(self, option, obj);
}
/* Failed to match any of the function signatures -- return error */
error:
PyErr_SetString(PyExc_TypeError, "invalid arguments to setopt");
return NULL;
}
PYCURL_INTERNAL PyObject *
do_curl_setopt_string(CurlObject *self, PyObject *args)
{
int option;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO:setopt", &option, &obj))
return NULL;
if (check_curl_state(self, 1 | 2, "setopt") != 0)
return NULL;
/* Handle the case of string arguments */
if (PyText_Check(obj)) {
return do_curl_setopt_string_impl(self, option, obj);
}
/* Failed to match any of the function signatures -- return error */
PyErr_SetString(PyExc_TypeError, "invalid arguments to setopt_string");
return NULL;
}
#if defined(HAVE_CURL_OPENSSL)
/* load ca certs from string */
PYCURL_INTERNAL PyObject *
do_curl_set_ca_certs(CurlObject *self, PyObject *args)
{
PyObject *cadata;
PyObject *encoded_obj;
char *buffer;
Py_ssize_t length;
int res;
if (!PyArg_ParseTuple(args, "O:cadata", &cadata))
return NULL;
// This may result in cadata string being encoded twice,
// not going to worry about it for now
if (!PyText_Check(cadata)) {
PyErr_SetString(PyExc_TypeError, "set_ca_certs argument must be a byte string or a Unicode string with ASCII code points only");
return NULL;
}
res = PyText_AsStringAndSize(cadata, &buffer, &length, &encoded_obj);
if (res) {
PyErr_SetString(PyExc_TypeError, "set_ca_certs argument must be a byte string or a Unicode string with ASCII code points only");
return NULL;
}
Py_CLEAR(self->ca_certs_obj);
if (encoded_obj) {
self->ca_certs_obj = encoded_obj;
} else {
Py_INCREF(cadata);
self->ca_certs_obj = cadata;
}
res = curl_easy_setopt(self->handle, CURLOPT_SSL_CTX_FUNCTION, (curl_ssl_ctx_callback) ssl_ctx_callback);
if (res != CURLE_OK) {
Py_CLEAR(self->ca_certs_obj);
CURLERROR_RETVAL();
}
res = curl_easy_setopt(self->handle, CURLOPT_SSL_CTX_DATA, self);
if (res != CURLE_OK) {
Py_CLEAR(self->ca_certs_obj);
CURLERROR_RETVAL();
}
Py_RETURN_NONE;
}
#endif
pycurl-7.43.0.2/src/oscompat.c 0000644 0001750 0001750 00000003103 13211045147 015062 0 ustar me me 0000000 0000000 #include "pycurl.h"
#if defined(WIN32)
PYCURL_INTERNAL int
dup_winsock(int sock, const struct curl_sockaddr *address)
{
int rv;
WSAPROTOCOL_INFO pi;
rv = WSADuplicateSocket(sock, GetCurrentProcessId(), &pi);
if (rv) {
return CURL_SOCKET_BAD;
}
/* not sure if WSA_FLAG_OVERLAPPED is needed, but it does not seem to hurt */
return (int) WSASocket(address->family, address->socktype, address->protocol, &pi, 0, WSA_FLAG_OVERLAPPED);
}
#endif
#if defined(WIN32) && ((_WIN32_WINNT < 0x0600) || (NTDDI_VERSION < NTDDI_VISTA))
/*
* Only Winsock on Vista+ has inet_ntop().
*/
PYCURL_INTERNAL const char *
pycurl_inet_ntop (int family, void *addr, char *string, size_t string_size)
{
SOCKADDR *sa;
int sa_len;
/* both size_t and DWORD should be unsigned ints */
DWORD string_size_dword = (DWORD) string_size;
if (family == AF_INET6) {
struct sockaddr_in6 sa6;
memset(&sa6, 0, sizeof(sa6));
sa6.sin6_family = AF_INET6;
memcpy(&sa6.sin6_addr, addr, sizeof(sa6.sin6_addr));
sa = (SOCKADDR*) &sa6;
sa_len = sizeof(sa6);
} else if (family == AF_INET) {
struct sockaddr_in sa4;
memset(&sa4, 0, sizeof(sa4));
sa4.sin_family = AF_INET;
memcpy(&sa4.sin_addr, addr, sizeof(sa4.sin_addr));
sa = (SOCKADDR*) &sa4;
sa_len = sizeof(sa4);
} else {
errno = EAFNOSUPPORT;
return NULL;
}
if (WSAAddressToString(sa, sa_len, NULL, string, &string_size_dword))
return NULL;
return string;
}
#endif
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/docstrings.h 0000644 0001750 0001750 00000002642 13304422053 015426 0 ustar me me 0000000 0000000 /* Generated file - do not edit. */
/* See doc/docstrings/ *.rst. */
extern const char curl_doc[];
extern const char curl_close_doc[];
extern const char curl_errstr_doc[];
extern const char curl_errstr_raw_doc[];
extern const char curl_getinfo_doc[];
extern const char curl_getinfo_raw_doc[];
extern const char curl_pause_doc[];
extern const char curl_perform_doc[];
extern const char curl_perform_rb_doc[];
extern const char curl_perform_rs_doc[];
extern const char curl_reset_doc[];
extern const char curl_set_ca_certs_doc[];
extern const char curl_setopt_doc[];
extern const char curl_setopt_string_doc[];
extern const char curl_unsetopt_doc[];
extern const char multi_doc[];
extern const char multi_add_handle_doc[];
extern const char multi_assign_doc[];
extern const char multi_close_doc[];
extern const char multi_fdset_doc[];
extern const char multi_info_read_doc[];
extern const char multi_perform_doc[];
extern const char multi_remove_handle_doc[];
extern const char multi_select_doc[];
extern const char multi_setopt_doc[];
extern const char multi_socket_action_doc[];
extern const char multi_socket_all_doc[];
extern const char multi_timeout_doc[];
extern const char pycurl_global_cleanup_doc[];
extern const char pycurl_global_init_doc[];
extern const char pycurl_module_doc[];
extern const char pycurl_version_info_doc[];
extern const char share_doc[];
extern const char share_close_doc[];
extern const char share_setopt_doc[];
pycurl-7.43.0.2/src/pycurl.h 0000644 0001750 0001750 00000045531 13301332107 014566 0 ustar me me 0000000 0000000 #if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32)
# define WIN32 1
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#if !defined(WIN32)
#include
#include
#include
#include
#endif
#if defined(WIN32)
/*
* Since setup.py uses a '-WX' in the CFLAGS (treat warnings as errors),
* the below will turn off some warnings when using MS-SDK 8.1+.
* This MUST be defined before including via the libcurl
* headers.
*/
# if !defined(_WINSOCK_DEPRECATED_NO_WARNINGS)
# define _WINSOCK_DEPRECATED_NO_WARNINGS
# endif
#endif
#include
#include
#include
#undef NDEBUG
#include
#define MAKE_LIBCURL_VERSION(major, minor, patch) \
((major) * 0x10000 + (minor) * 0x100 + (patch))
/* spot check */
#if MAKE_LIBCURL_VERSION(7, 21, 16) != 0x071510
# error MAKE_LIBCURL_VERSION is not working correctly
#endif
#if defined(PYCURL_SINGLE_FILE)
# define PYCURL_INTERNAL static
#else
# define PYCURL_INTERNAL
#endif
#if defined(WIN32)
/* supposedly not present in errno.h provided with VC */
# if !defined(EAFNOSUPPORT)
# define EAFNOSUPPORT 97
# endif
PYCURL_INTERNAL int
dup_winsock(int sock, const struct curl_sockaddr *address);
#endif
/* The inet_ntop() was added in ws2_32.dll on Windows Vista [1]. Hence the
* Windows SDK targeting lesser OS'es doesn't provide that prototype.
* Maybe we should use the local hidden inet_ntop() for all OS'es thus
* making a pycurl.pyd work across OS'es w/o rebuilding?
*
* [1] http://msdn.microsoft.com/en-us/library/windows/desktop/cc805843(v=vs.85).aspx
*/
#if defined(WIN32) && ((_WIN32_WINNT < 0x0600) || (NTDDI_VERSION < NTDDI_VISTA))
PYCURL_INTERNAL const char *
pycurl_inet_ntop (int family, void *addr, char *string, size_t string_size);
#define inet_ntop(fam,addr,string,size) pycurl_inet_ntop(fam,addr,string,size)
#endif
#if !defined(LIBCURL_VERSION_NUM) || (LIBCURL_VERSION_NUM < 0x071300)
# error "Need libcurl version 7.19.0 or greater to compile pycurl."
#endif
#if LIBCURL_VERSION_NUM >= 0x071301 /* check for 7.19.1 or greater */
#define HAVE_CURLOPT_USERNAME
#define HAVE_CURLOPT_PROXYUSERNAME
#define HAVE_CURLOPT_CERTINFO
#define HAVE_CURLOPT_POSTREDIR
#endif
#if LIBCURL_VERSION_NUM >= 0x071303 /* check for 7.19.3 or greater */
#define HAVE_CURLAUTH_DIGEST_IE
#endif
#if LIBCURL_VERSION_NUM >= 0x071304 /* check for 7.19.4 or greater */
#define HAVE_CURLOPT_NOPROXY
#define HAVE_CURLOPT_PROTOCOLS
#define HAVE_CURL_7_19_4_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071305 /* check for 7.19.5 or greater */
#define HAVE_CURL_7_19_5_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071306 /* check for 7.19.6 or greater */
#define HAVE_CURL_7_19_6_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071400 /* check for 7.20.0 or greater */
#define HAVE_CURL_7_20_0_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071500 /* check for 7.21.0 or greater */
#define HAVE_CURLINFO_LOCAL_PORT
#define HAVE_CURLINFO_PRIMARY_PORT
#define HAVE_CURLINFO_LOCAL_IP
#define HAVE_CURL_7_21_0_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071502 /* check for 7.21.2 or greater */
#define HAVE_CURL_7_21_2_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071503 /* check for 7.21.3 or greater */
#define HAVE_CURLOPT_RESOLVE
#endif
#if LIBCURL_VERSION_NUM >= 0x071505 /* check for 7.21.5 or greater */
#define HAVE_CURL_7_21_5
#endif
#if LIBCURL_VERSION_NUM >= 0x071600 /* check for 7.22.0 or greater */
#define HAVE_CURL_7_22_0_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071800 /* check for 7.24.0 or greater */
#define HAVE_CURLOPT_DNS_SERVERS
#define HAVE_CURL_7_24_0
#endif
#if LIBCURL_VERSION_NUM >= 0x071900 /* check for 7.25.0 or greater */
#define HAVE_CURL_7_25_0_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x071A00 /* check for 7.26.0 or greater */
#define HAVE_CURL_REDIR_POST_303
#endif
#if LIBCURL_VERSION_NUM >= 0x071E00 /* check for 7.30.0 or greater */
#define HAVE_CURL_7_30_0_PIPELINE_OPTS
#endif
#if LIBCURL_VERSION_NUM >= 0x073100 /* check for 7.49.0 or greater */
#define HAVE_CURLOPT_CONNECT_TO
#endif
#if LIBCURL_VERSION_NUM >= 0x073200 /* check for 7.50.0 or greater */
#define HAVE_CURLINFO_HTTP_VERSION
#endif
#undef UNUSED
#define UNUSED(var) ((void)&var)
/* Cruft for thread safe SSL crypto locks, snapped from the PHP curl extension */
#if defined(HAVE_CURL_SSL)
# if defined(HAVE_CURL_OPENSSL)
# define PYCURL_NEED_SSL_TSL
# define PYCURL_NEED_OPENSSL_TSL
# include
# include
# define COMPILE_SSL_LIB "openssl"
# elif defined(HAVE_CURL_GNUTLS)
# include
# if GNUTLS_VERSION_NUMBER <= 0x020b00
# define PYCURL_NEED_SSL_TSL
# define PYCURL_NEED_GNUTLS_TSL
# include
# endif
# define COMPILE_SSL_LIB "gnutls"
# elif defined(HAVE_CURL_NSS)
# define COMPILE_SSL_LIB "nss"
# else
# ifdef _MSC_VER
/* sigh */
# pragma message(\
"libcurl was compiled with SSL support, but configure could not determine which " \
"library was used; thus no SSL crypto locking callbacks will be set, which may " \
"cause random crashes on SSL requests")
# else
# warning \
"libcurl was compiled with SSL support, but configure could not determine which " \
"library was used; thus no SSL crypto locking callbacks will be set, which may " \
"cause random crashes on SSL requests"
# endif
/* since we have no crypto callbacks for other ssl backends,
* no reason to require users match those */
# define COMPILE_SSL_LIB "none/other"
# endif /* HAVE_CURL_OPENSSL || HAVE_CURL_GNUTLS || HAVE_CURL_NSS */
#else
# define COMPILE_SSL_LIB "none/other"
#endif /* HAVE_CURL_SSL */
#if defined(PYCURL_NEED_SSL_TSL)
PYCURL_INTERNAL int pycurl_ssl_init(void);
PYCURL_INTERNAL void pycurl_ssl_cleanup(void);
#endif
#ifdef WITH_THREAD
# define PYCURL_DECLARE_THREAD_STATE PyThreadState *tmp_state
# define PYCURL_ACQUIRE_THREAD() pycurl_acquire_thread(self, &tmp_state)
# define PYCURL_ACQUIRE_THREAD_MULTI() pycurl_acquire_thread_multi(self, &tmp_state)
# define PYCURL_RELEASE_THREAD() pycurl_release_thread(tmp_state)
/* Replacement for Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS when python
callbacks are expected during blocking i/o operations: self->state will hold
the handle to current thread to be used as context */
# define PYCURL_BEGIN_ALLOW_THREADS \
self->state = PyThreadState_Get(); \
assert(self->state != NULL); \
Py_BEGIN_ALLOW_THREADS
# define PYCURL_END_ALLOW_THREADS \
Py_END_ALLOW_THREADS \
self->state = NULL;
#else
# define PYCURL_DECLARE_THREAD_STATE
# define PYCURL_ACQUIRE_THREAD() (1)
# define PYCURL_ACQUIRE_THREAD_MULTI() (1)
# define PYCURL_RELEASE_THREAD()
# define PYCURL_BEGIN_ALLOW_THREADS
# define PYCURL_END_ALLOW_THREADS
#endif
#if PY_MAJOR_VERSION >= 3
#define PyInt_Type PyLong_Type
#define PyInt_Check(op) PyLong_Check(op)
#define PyInt_FromLong PyLong_FromLong
#define PyInt_AsLong PyLong_AsLong
#endif
#define PYLISTORTUPLE_LIST 1
#define PYLISTORTUPLE_TUPLE 2
#define PYLISTORTUPLE_OTHER 0
PYCURL_INTERNAL int
PyListOrTuple_Check(PyObject *v);
PYCURL_INTERNAL Py_ssize_t
PyListOrTuple_Size(PyObject *v, int which);
PYCURL_INTERNAL PyObject *
PyListOrTuple_GetItem(PyObject *v, Py_ssize_t i, int which);
/*************************************************************************
// python 2/3 compatibility
**************************************************************************/
#if PY_MAJOR_VERSION >= 3
# define PyText_FromFormat(format, str) PyUnicode_FromFormat((format), (str))
# define PyText_FromString(str) PyUnicode_FromString(str)
# define PyByteStr_FromString(str) PyBytes_FromString(str)
# define PyByteStr_Check(obj) PyBytes_Check(obj)
# define PyByteStr_AsStringAndSize(obj, buffer, length) PyBytes_AsStringAndSize((obj), (buffer), (length))
#else
# define PyText_FromFormat(format, str) PyString_FromFormat((format), (str))
# define PyText_FromString(str) PyString_FromString(str)
# define PyByteStr_FromString(str) PyString_FromString(str)
# define PyByteStr_Check(obj) PyString_Check(obj)
# define PyByteStr_AsStringAndSize(obj, buffer, length) PyString_AsStringAndSize((obj), (buffer), (length))
#endif
#define PyText_EncodedDecref(encoded) Py_XDECREF(encoded)
PYCURL_INTERNAL int
PyText_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length, PyObject **encoded_obj);
PYCURL_INTERNAL char *
PyText_AsString_NoNUL(PyObject *obj, PyObject **encoded_obj);
PYCURL_INTERNAL int
PyText_Check(PyObject *o);
PYCURL_INTERNAL PyObject *
PyText_FromString_Ignore(const char *string);
struct CurlObject;
PYCURL_INTERNAL void
create_and_set_error_object(struct CurlObject *self, int code);
/* Raise exception based on return value `res' and `self->error' */
#define CURLERROR_RETVAL() do {\
create_and_set_error_object((self), (int) (res)); \
return NULL; \
} while (0)
#define CURLERROR_SET_RETVAL() \
create_and_set_error_object((self), (int) (res));
#define CURLERROR_RETVAL_MULTI_DONE() do {\
PyObject *v; \
v = Py_BuildValue("(i)", (int) (res)); \
if (v != NULL) { PyErr_SetObject(ErrorObject, v); Py_DECREF(v); } \
goto done; \
} while (0)
/* Raise exception based on return value `res' and custom message */
/* msg should be ASCII */
#define CURLERROR_MSG(msg) do {\
PyObject *v; const char *m = (msg); \
v = Py_BuildValue("(is)", (int) (res), (m)); \
if (v != NULL) { PyErr_SetObject(ErrorObject, v); Py_DECREF(v); } \
return NULL; \
} while (0)
/* Calculate the number of OBJECTPOINT options we need to store */
#define OPTIONS_SIZE ((int)CURLOPT_LASTENTRY % 10000)
#define MOPTIONS_SIZE ((int)CURLMOPT_LASTENTRY % 10000)
/* Memory groups */
/* Attributes dictionary */
#define PYCURL_MEMGROUP_ATTRDICT 1
/* multi_stack */
#define PYCURL_MEMGROUP_MULTI 2
/* Python callbacks */
#define PYCURL_MEMGROUP_CALLBACK 4
/* Python file objects */
#define PYCURL_MEMGROUP_FILE 8
/* Share objects */
#define PYCURL_MEMGROUP_SHARE 16
/* httppost buffer references */
#define PYCURL_MEMGROUP_HTTPPOST 32
/* Postfields object */
#define PYCURL_MEMGROUP_POSTFIELDS 64
/* CA certs object */
#define PYCURL_MEMGROUP_CACERTS 128
#define PYCURL_MEMGROUP_EASY \
(PYCURL_MEMGROUP_CALLBACK | PYCURL_MEMGROUP_FILE | \
PYCURL_MEMGROUP_HTTPPOST | PYCURL_MEMGROUP_POSTFIELDS | \
PYCURL_MEMGROUP_CACERTS)
#define PYCURL_MEMGROUP_ALL \
(PYCURL_MEMGROUP_ATTRDICT | PYCURL_MEMGROUP_EASY | \
PYCURL_MEMGROUP_MULTI | PYCURL_MEMGROUP_SHARE)
typedef struct CurlObject {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
// https://docs.python.org/3/extending/newtypes.html
PyObject *weakreflist;
CURL *handle;
#ifdef WITH_THREAD
PyThreadState *state;
#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;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
struct curl_slist *proxyheader;
#endif
struct curl_slist *http200aliases;
struct curl_slist *quote;
struct curl_slist *postquote;
struct curl_slist *prequote;
struct curl_slist *telnetoptions;
#ifdef HAVE_CURLOPT_RESOLVE
struct curl_slist *resolve;
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
struct curl_slist *mail_rcpt;
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
struct curl_slist *connect_to;
#endif
/* callbacks */
PyObject *w_cb;
PyObject *h_cb;
PyObject *r_cb;
PyObject *pro_cb;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
PyObject *xferinfo_cb;
#endif
PyObject *debug_cb;
PyObject *ioctl_cb;
PyObject *opensocket_cb;
#if LIBCURL_VERSION_NUM >= 0x071507 /* check for 7.21.7 or greater */
PyObject *closesocket_cb;
#endif
PyObject *seek_cb;
PyObject *sockopt_cb;
PyObject *ssh_key_cb;
/* file objects */
PyObject *readdata_fp;
PyObject *writedata_fp;
PyObject *writeheader_fp;
/* reference to the object used for CURLOPT_POSTFIELDS */
PyObject *postfields_obj;
/* reference to the object containing ca certs */
PyObject *ca_certs_obj;
/* misc */
char error[CURL_ERROR_SIZE+1];
} CurlObject;
typedef struct CurlMultiObject {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
// https://docs.python.org/3/extending/newtypes.html
PyObject *weakreflist;
CURLM *multi_handle;
#ifdef WITH_THREAD
PyThreadState *state;
#endif
fd_set read_fd_set;
fd_set write_fd_set;
fd_set exc_fd_set;
/* callbacks */
PyObject *t_cb;
PyObject *s_cb;
PyObject *easy_object_dict;
} CurlMultiObject;
typedef struct {
PyThread_type_lock locks[CURL_LOCK_DATA_LAST];
} ShareLock;
typedef struct CurlShareObject {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
// https://docs.python.org/3/extending/newtypes.html
PyObject *weakreflist;
CURLSH *share_handle;
#ifdef WITH_THREAD
ShareLock *lock; /* lock object to implement CURLSHOPT_LOCKFUNC */
#endif
} CurlShareObject;
#ifdef WITH_THREAD
PYCURL_INTERNAL PyThreadState *
pycurl_get_thread_state(const CurlObject *self);
PYCURL_INTERNAL PyThreadState *
pycurl_get_thread_state_multi(const CurlMultiObject *self);
PYCURL_INTERNAL int
pycurl_acquire_thread(const CurlObject *self, PyThreadState **state);
PYCURL_INTERNAL int
pycurl_acquire_thread_multi(const CurlMultiObject *self, PyThreadState **state);
PYCURL_INTERNAL void
pycurl_release_thread(PyThreadState *state);
PYCURL_INTERNAL void
share_lock_lock(ShareLock *lock, curl_lock_data data);
PYCURL_INTERNAL void
share_lock_unlock(ShareLock *lock, curl_lock_data data);
PYCURL_INTERNAL ShareLock *
share_lock_new(void);
PYCURL_INTERNAL void
share_lock_destroy(ShareLock *lock);
PYCURL_INTERNAL void
share_lock_callback(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
PYCURL_INTERNAL void
share_unlock_callback(CURL *handle, curl_lock_data data, void *userptr);
#endif /* WITH_THREAD */
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
my_getattro(PyObject *co, PyObject *name, PyObject *dict1, PyObject *dict2, PyMethodDef *m);
PYCURL_INTERNAL int
my_setattro(PyObject **dict, PyObject *name, PyObject *v);
#else /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL int
my_setattr(PyObject **dict, char *name, PyObject *v);
PYCURL_INTERNAL PyObject *
my_getattr(PyObject *co, char *name, PyObject *dict1, PyObject *dict2, PyMethodDef *m);
#endif /* PY_MAJOR_VERSION >= 3 */
/* used by multi object */
PYCURL_INTERNAL void
assert_curl_state(const CurlObject *self);
PYCURL_INTERNAL PyObject *
do_global_init(PyObject *dummy, PyObject *args);
PYCURL_INTERNAL PyObject *
do_global_cleanup(PyObject *dummy);
PYCURL_INTERNAL PyObject *
do_version_info(PyObject *dummy, PyObject *args);
PYCURL_INTERNAL PyObject *
do_curl_setopt(CurlObject *self, PyObject *args);
PYCURL_INTERNAL PyObject *
do_curl_setopt_string(CurlObject *self, PyObject *args);
PYCURL_INTERNAL PyObject *
do_curl_unsetopt(CurlObject *self, PyObject *args);
#if defined(HAVE_CURL_OPENSSL)
PYCURL_INTERNAL PyObject *
do_curl_set_ca_certs(CurlObject *self, PyObject *args);
#endif
PYCURL_INTERNAL PyObject *
do_curl_perform(CurlObject *self);
PYCURL_INTERNAL PyObject *
do_curl_perform_rb(CurlObject *self);
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_perform_rs(CurlObject *self);
#else
# define do_curl_perform_rs do_curl_perform_rb
#endif
PYCURL_INTERNAL PyObject *
do_curl_pause(CurlObject *self, PyObject *args);
PYCURL_INTERNAL int
check_curl_state(const CurlObject *self, int flags, const char *name);
PYCURL_INTERNAL void
util_curl_xdecref(CurlObject *self, int flags, CURL *handle);
PYCURL_INTERNAL PyObject *
do_curl_setopt_filelike(CurlObject *self, int option, PyObject *obj);
PYCURL_INTERNAL PyObject *
do_curl_getinfo_raw(CurlObject *self, PyObject *args);
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_getinfo(CurlObject *self, PyObject *args);
#else
# define do_curl_getinfo do_curl_getinfo_raw
#endif
PYCURL_INTERNAL PyObject *
do_curl_errstr(CurlObject *self);
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_errstr_raw(CurlObject *self);
#else
# define do_curl_errstr_raw do_curl_errstr
#endif
PYCURL_INTERNAL size_t
write_callback(char *ptr, size_t size, size_t nmemb, void *stream);
PYCURL_INTERNAL size_t
header_callback(char *ptr, size_t size, size_t nmemb, void *stream);
PYCURL_INTERNAL curl_socket_t
opensocket_callback(void *clientp, curlsocktype purpose,
struct curl_sockaddr *address);
PYCURL_INTERNAL int
sockopt_cb(void *clientp, curl_socket_t curlfd, curlsocktype purpose);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
PYCURL_INTERNAL int
closesocket_callback(void *clientp, curl_socket_t curlfd);
#endif
#ifdef HAVE_CURL_7_19_6_OPTS
PYCURL_INTERNAL int
ssh_key_cb(CURL *easy, const struct curl_khkey *knownkey,
const struct curl_khkey *foundkey, int khmatch, void *clientp);
#endif
PYCURL_INTERNAL int
seek_callback(void *stream, curl_off_t offset, int origin);
PYCURL_INTERNAL size_t
read_callback(char *ptr, size_t size, size_t nmemb, void *stream);
PYCURL_INTERNAL int
progress_callback(void *stream,
double dltotal, double dlnow, double ultotal, double ulnow);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
PYCURL_INTERNAL int
xferinfo_callback(void *stream,
curl_off_t dltotal, curl_off_t dlnow,
curl_off_t ultotal, curl_off_t ulnow);
#endif
PYCURL_INTERNAL int
debug_callback(CURL *curlobj, curl_infotype type,
char *buffer, size_t total_size, void *stream);
PYCURL_INTERNAL curlioerr
ioctl_callback(CURL *curlobj, int cmd, void *stream);
#if defined(HAVE_CURL_OPENSSL)
PYCURL_INTERNAL CURLcode
ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *ptr);
#endif
#if !defined(PYCURL_SINGLE_FILE)
/* Type objects */
extern PyTypeObject Curl_Type;
extern PyTypeObject CurlMulti_Type;
extern PyTypeObject CurlShare_Type;
extern PyObject *ErrorObject;
extern PyTypeObject *p_Curl_Type;
extern PyTypeObject *p_CurlMulti_Type;
extern PyTypeObject *p_CurlShare_Type;
extern PyObject *khkey_type;
extern PyObject *curl_sockaddr_type;
extern PyObject *curlobject_constants;
extern PyObject *curlmultiobject_constants;
extern PyObject *curlshareobject_constants;
extern char *g_pycurl_useragent;
extern PYCURL_INTERNAL char *empty_keywords[];
extern PYCURL_INTERNAL PyObject *bytesio;
extern PYCURL_INTERNAL PyObject *stringio;
#if PY_MAJOR_VERSION >= 3
extern PyMethodDef curlobject_methods[];
extern PyMethodDef curlshareobject_methods[];
extern PyMethodDef curlmultiobject_methods[];
#endif
#endif /* !PYCURL_SINGLE_FILE */
#if PY_MAJOR_VERSION >= 3
# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC
#else
# define PYCURL_TYPE_FLAGS Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS
#endif
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/easyperform.c 0000644 0001750 0001750 00000004505 13301332107 015573 0 ustar me me 0000000 0000000 #include "pycurl.h"
/* --------------- perform --------------- */
PYCURL_INTERNAL PyObject *
do_curl_perform(CurlObject *self)
{
int res;
if (check_curl_state(self, 1 | 2, "perform") != 0) {
return NULL;
}
PYCURL_BEGIN_ALLOW_THREADS
res = curl_easy_perform(self->handle);
PYCURL_END_ALLOW_THREADS
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
Py_RETURN_NONE;
}
PYCURL_INTERNAL PyObject *
do_curl_perform_rb(CurlObject *self)
{
PyObject *v, *io;
io = PyEval_CallObject(bytesio, NULL);
if (io == NULL) {
return NULL;
}
v = do_curl_setopt_filelike(self, CURLOPT_WRITEDATA, io);
if (v == NULL) {
Py_DECREF(io);
return NULL;
}
v = do_curl_perform(self);
if (v == NULL) {
return NULL;
}
v = PyObject_CallMethod(io, "getvalue", NULL);
Py_DECREF(io);
return v;
}
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_perform_rs(CurlObject *self)
{
PyObject *v, *decoded;
v = do_curl_perform_rb(self);
if (v == NULL) {
return NULL;
}
decoded = PyUnicode_FromEncodedObject(v, NULL, NULL);
Py_DECREF(v);
return decoded;
}
#endif
/* --------------- pause --------------- */
/* curl_easy_pause() can be called from inside a callback or outside */
PYCURL_INTERNAL PyObject *
do_curl_pause(CurlObject *self, PyObject *args)
{
int bitmask;
CURLcode res;
#ifdef WITH_THREAD
PyThreadState *saved_state;
#endif
if (!PyArg_ParseTuple(args, "i:pause", &bitmask)) {
return NULL;
}
if (check_curl_state(self, 1, "pause") != 0) {
return NULL;
}
#ifdef WITH_THREAD
/* Save handle to current thread (used as context for python callbacks) */
saved_state = self->state;
PYCURL_BEGIN_ALLOW_THREADS
/* We must allow threads here because unpausing a handle can cause
some of its callbacks to be invoked immediately, from inside
curl_easy_pause() */
#endif
res = curl_easy_pause(self->handle, bitmask);
#ifdef WITH_THREAD
PYCURL_END_ALLOW_THREADS
/* Restore the thread-state to whatever it was on entry */
self->state = saved_state;
#endif
if (res != CURLE_OK) {
CURLERROR_MSG("pause/unpause failed");
} else {
Py_INCREF(Py_None);
return Py_None;
}
}
pycurl-7.43.0.2/src/pythoncompat.c 0000644 0001750 0001750 00000005673 13211045147 016000 0 ustar me me 0000000 0000000 #include "pycurl.h"
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
my_getattro(PyObject *co, PyObject *name, PyObject *dict1, PyObject *dict2, PyMethodDef *m)
{
PyObject *v = NULL;
if( dict1 != NULL )
v = PyDict_GetItem(dict1, name);
if( v == NULL && dict2 != NULL )
v = PyDict_GetItem(dict2, name);
if( v != NULL )
{
Py_INCREF(v);
return v;
}
PyErr_SetString(PyExc_AttributeError, "trying to obtain a non-existing attribute");
return NULL;
}
PYCURL_INTERNAL int
my_setattro(PyObject **dict, PyObject *name, PyObject *v)
{
if( *dict == NULL )
{
*dict = PyDict_New();
if( *dict == NULL )
return -1;
}
if (v != NULL)
return PyDict_SetItem(*dict, name, v);
else {
int v = PyDict_DelItem(*dict, name);
if (v != 0) {
/* need to convert KeyError to AttributeError */
if (PyErr_ExceptionMatches(PyExc_KeyError)) {
PyErr_SetString(PyExc_AttributeError, "trying to delete a non-existing attribute");
}
}
return v;
}
}
#else /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL int
my_setattr(PyObject **dict, char *name, PyObject *v)
{
if (v == NULL) {
int rv = -1;
if (*dict != NULL)
rv = PyDict_DelItemString(*dict, name);
if (rv < 0)
PyErr_SetString(PyExc_AttributeError, "delete non-existing attribute");
return rv;
}
if (*dict == NULL) {
*dict = PyDict_New();
if (*dict == NULL)
return -1;
}
return PyDict_SetItemString(*dict, name, v);
}
PYCURL_INTERNAL PyObject *
my_getattr(PyObject *co, char *name, PyObject *dict1, PyObject *dict2, PyMethodDef *m)
{
PyObject *v = NULL;
if (v == NULL && dict1 != NULL)
v = PyDict_GetItemString(dict1, name);
if (v == NULL && dict2 != NULL)
v = PyDict_GetItemString(dict2, name);
if (v != NULL) {
Py_INCREF(v);
return v;
}
return Py_FindMethod(m, co, name);
}
#endif /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL int
PyListOrTuple_Check(PyObject *v)
{
int result;
if (PyList_Check(v)) {
result = PYLISTORTUPLE_LIST;
} else if (PyTuple_Check(v)) {
result = PYLISTORTUPLE_TUPLE;
} else {
result = PYLISTORTUPLE_OTHER;
}
return result;
}
PYCURL_INTERNAL Py_ssize_t
PyListOrTuple_Size(PyObject *v, int which)
{
switch (which) {
case PYLISTORTUPLE_LIST:
return PyList_Size(v);
case PYLISTORTUPLE_TUPLE:
return PyTuple_Size(v);
default:
assert(0);
return 0;
}
}
PYCURL_INTERNAL PyObject *
PyListOrTuple_GetItem(PyObject *v, Py_ssize_t i, int which)
{
switch (which) {
case PYLISTORTUPLE_LIST:
return PyList_GetItem(v, i);
case PYLISTORTUPLE_TUPLE:
return PyTuple_GetItem(v, i);
default:
assert(0);
return NULL;
}
}
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/threadsupport.c 0000644 0001750 0001750 00000016327 13277672061 016172 0 ustar me me 0000000 0000000 #include "pycurl.h"
#ifdef WITH_THREAD
PYCURL_INTERNAL PyThreadState *
pycurl_get_thread_state(const CurlObject *self)
{
/* Get the thread state for callbacks to run in.
* This is either `self->state' when running inside perform() or
* `self->multi_stack->state' when running inside multi_perform().
* When the result is != NULL we also implicitly assert
* a valid `self->handle'.
*/
if (self == NULL)
return NULL;
assert(Py_TYPE(self) == p_Curl_Type);
if (self->state != NULL)
{
/* inside perform() */
assert(self->handle != NULL);
if (self->multi_stack != NULL) {
assert(self->multi_stack->state == NULL);
}
return self->state;
}
if (self->multi_stack != NULL && self->multi_stack->state != NULL)
{
/* inside multi_perform() */
assert(self->handle != NULL);
assert(self->multi_stack->multi_handle != NULL);
assert(self->state == NULL);
return self->multi_stack->state;
}
return NULL;
}
PYCURL_INTERNAL PyThreadState *
pycurl_get_thread_state_multi(const CurlMultiObject *self)
{
/* Get the thread state for callbacks to run in when given
* multi handles instead of regular handles
*/
if (self == NULL)
return NULL;
assert(Py_TYPE(self) == p_CurlMulti_Type);
if (self->state != NULL)
{
/* inside multi_perform() */
assert(self->multi_handle != NULL);
return self->state;
}
return NULL;
}
PYCURL_INTERNAL int
pycurl_acquire_thread(const CurlObject *self, PyThreadState **state)
{
*state = pycurl_get_thread_state(self);
if (*state == NULL)
return 0;
PyEval_AcquireThread(*state);
return 1;
}
PYCURL_INTERNAL int
pycurl_acquire_thread_multi(const CurlMultiObject *self, PyThreadState **state)
{
*state = pycurl_get_thread_state_multi(self);
if (*state == NULL)
return 0;
PyEval_AcquireThread(*state);
return 1;
}
PYCURL_INTERNAL void
pycurl_release_thread(PyThreadState *state)
{
PyEval_ReleaseThread(state);
}
/*************************************************************************
// SSL TSL
**************************************************************************/
#ifdef PYCURL_NEED_OPENSSL_TSL
#if OPENSSL_VERSION_NUMBER < 0x10100000
static PyThread_type_lock *pycurl_openssl_tsl = NULL;
static void
pycurl_ssl_lock(int mode, int n, const char * file, int line)
{
if (mode & CRYPTO_LOCK) {
PyThread_acquire_lock(pycurl_openssl_tsl[n], 1);
} else {
PyThread_release_lock(pycurl_openssl_tsl[n]);
}
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000
/* use new CRYPTO_THREADID API. */
static void
pycurl_ssl_threadid_callback(CRYPTO_THREADID *id)
{
CRYPTO_THREADID_set_numeric(id, (unsigned long)PyThread_get_thread_ident());
}
#else
/* deprecated CRYPTO_set_id_callback() API. */
static unsigned long
pycurl_ssl_id(void)
{
return (unsigned long) PyThread_get_thread_ident();
}
#endif
#endif
PYCURL_INTERNAL int
pycurl_ssl_init(void)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000
int i, c = CRYPTO_num_locks();
pycurl_openssl_tsl = PyMem_New(PyThread_type_lock, c);
if (pycurl_openssl_tsl == NULL) {
PyErr_NoMemory();
return -1;
}
memset(pycurl_openssl_tsl, 0, sizeof(PyThread_type_lock) * c);
for (i = 0; i < c; ++i) {
pycurl_openssl_tsl[i] = PyThread_allocate_lock();
if (pycurl_openssl_tsl[i] == NULL) {
for (--i; i >= 0; --i) {
PyThread_free_lock(pycurl_openssl_tsl[i]);
}
PyMem_Free(pycurl_openssl_tsl);
PyErr_NoMemory();
return -1;
}
}
#if OPENSSL_VERSION_NUMBER >= 0x10000000
CRYPTO_THREADID_set_callback(pycurl_ssl_threadid_callback);
#else
CRYPTO_set_id_callback(pycurl_ssl_id);
#endif
CRYPTO_set_locking_callback(pycurl_ssl_lock);
#endif
return 0;
}
PYCURL_INTERNAL void
pycurl_ssl_cleanup(void)
{
#if OPENSSL_VERSION_NUMBER < 0x10100000
if (pycurl_openssl_tsl) {
int i, c = CRYPTO_num_locks();
#if OPENSSL_VERSION_NUMBER >= 0x10000000
CRYPTO_THREADID_set_callback(NULL);
#else
CRYPTO_set_id_callback(NULL);
#endif
CRYPTO_set_locking_callback(NULL);
for (i = 0; i < c; ++i) {
PyThread_free_lock(pycurl_openssl_tsl[i]);
}
PyMem_Free(pycurl_openssl_tsl);
pycurl_openssl_tsl = NULL;
}
#endif
}
#endif
#ifdef PYCURL_NEED_GNUTLS_TSL
static int
pycurl_ssl_mutex_create(void **m)
{
if ((*((PyThread_type_lock *) m) = PyThread_allocate_lock()) == NULL) {
return -1;
} else {
return 0;
}
}
static int
pycurl_ssl_mutex_destroy(void **m)
{
PyThread_free_lock(*((PyThread_type_lock *) m));
return 0;
}
static int
pycurl_ssl_mutex_lock(void **m)
{
return !PyThread_acquire_lock(*((PyThread_type_lock *) m), 1);
}
static int
pycurl_ssl_mutex_unlock(void **m)
{
PyThread_release_lock(*((PyThread_type_lock *) m));
return 0;
}
static struct gcry_thread_cbs pycurl_gnutls_tsl = {
GCRY_THREAD_OPTION_USER,
NULL,
pycurl_ssl_mutex_create,
pycurl_ssl_mutex_destroy,
pycurl_ssl_mutex_lock,
pycurl_ssl_mutex_unlock
};
PYCURL_INTERNAL int
pycurl_ssl_init(void)
{
gcry_control(GCRYCTL_SET_THREAD_CBS, &pycurl_gnutls_tsl);
return 0;
}
PYCURL_INTERNAL void
pycurl_ssl_cleanup(void)
{
return;
}
#endif
/*************************************************************************
// CurlShareObject
**************************************************************************/
PYCURL_INTERNAL void
share_lock_lock(ShareLock *lock, curl_lock_data data)
{
PyThread_acquire_lock(lock->locks[data], 1);
}
PYCURL_INTERNAL void
share_lock_unlock(ShareLock *lock, curl_lock_data data)
{
PyThread_release_lock(lock->locks[data]);
}
PYCURL_INTERNAL ShareLock *
share_lock_new(void)
{
int i;
ShareLock *lock = PyMem_New(ShareLock, 1);
if (lock == NULL) {
PyErr_NoMemory();
return NULL;
}
for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
lock->locks[i] = PyThread_allocate_lock();
if (lock->locks[i] == NULL) {
PyErr_NoMemory();
goto error;
}
}
return lock;
error:
for (--i; i >= 0; --i) {
PyThread_free_lock(lock->locks[i]);
lock->locks[i] = NULL;
}
PyMem_Free(lock);
return NULL;
}
PYCURL_INTERNAL void
share_lock_destroy(ShareLock *lock)
{
int i;
assert(lock);
for (i = 0; i < CURL_LOCK_DATA_LAST; ++i){
assert(lock->locks[i] != NULL);
PyThread_free_lock(lock->locks[i]);
}
PyMem_Free(lock);
lock = NULL;
}
PYCURL_INTERNAL void
share_lock_callback(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
{
CurlShareObject *share = (CurlShareObject*)userptr;
share_lock_lock(share->lock, data);
}
PYCURL_INTERNAL void
share_unlock_callback(CURL *handle, curl_lock_data data, void *userptr)
{
CurlShareObject *share = (CurlShareObject*)userptr;
share_lock_unlock(share->lock, data);
}
#else /* WITH_THREAD */
#if defined(PYCURL_NEED_SSL_TSL)
PYCURL_INTERNAL void
pycurl_ssl_init(void)
{
return 0;
}
PYCURL_INTERNAL void
pycurl_ssl_cleanup(void)
{
return;
}
#endif
#endif /* WITH_THREAD */
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/easy.c 0000644 0001750 0001750 00000040322 13301332107 014175 0 ustar me me 0000000 0000000 #include "pycurl.h"
#include "docstrings.h"
/*************************************************************************
// static utility functions
**************************************************************************/
/* assert some CurlObject invariants */
PYCURL_INTERNAL void
assert_curl_state(const CurlObject *self)
{
assert(self != NULL);
assert(Py_TYPE(self) == p_Curl_Type);
#ifdef WITH_THREAD
(void) pycurl_get_thread_state(self);
#endif
}
/* check state for methods */
PYCURL_INTERNAL int
check_curl_state(const CurlObject *self, int flags, const char *name)
{
assert_curl_state(self);
if ((flags & 1) && self->handle == NULL) {
PyErr_Format(ErrorObject, "cannot invoke %s() - no curl handle", name);
return -1;
}
#ifdef WITH_THREAD
if ((flags & 2) && pycurl_get_thread_state(self) != NULL) {
PyErr_Format(ErrorObject, "cannot invoke %s() - perform() is currently running", name);
return -1;
}
#endif
return 0;
}
/*************************************************************************
// CurlObject
**************************************************************************/
/* --------------- construct/destruct (i.e. open/close) --------------- */
/* initializer - used to intialize curl easy handles for use with pycurl */
static int
util_curl_init(CurlObject *self)
{
int res;
/* Set curl error buffer and zero it */
res = curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->error);
if (res != CURLE_OK) {
return (-1);
}
memset(self->error, 0, sizeof(self->error));
/* Set backreference */
res = curl_easy_setopt(self->handle, CURLOPT_PRIVATE, (char *) self);
if (res != CURLE_OK) {
return (-1);
}
/* Enable NOPROGRESS by default, i.e. no progress output */
res = curl_easy_setopt(self->handle, CURLOPT_NOPROGRESS, (long)1);
if (res != CURLE_OK) {
return (-1);
}
/* Disable VERBOSE by default, i.e. no verbose output */
res = curl_easy_setopt(self->handle, CURLOPT_VERBOSE, (long)0);
if (res != CURLE_OK) {
return (-1);
}
/* Set FTP_ACCOUNT to NULL by default */
res = curl_easy_setopt(self->handle, CURLOPT_FTP_ACCOUNT, NULL);
if (res != CURLE_OK) {
return (-1);
}
/* Set default USERAGENT */
assert(g_pycurl_useragent);
res = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, g_pycurl_useragent);
if (res != CURLE_OK) {
return (-1);
}
return (0);
}
/* constructor */
PYCURL_INTERNAL CurlObject *
do_curl_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
CurlObject *self;
int res;
int *ptr;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
return NULL;
}
/* Allocate python curl object */
self = (CurlObject *) p_Curl_Type->tp_alloc(p_Curl_Type, 0);
if (self == NULL)
return NULL;
/* tp_alloc is expected to return zeroed memory */
for (ptr = (int *) &self->dict;
ptr < (int *) (((char *) self) + sizeof(CurlObject));
++ptr)
assert(*ptr == 0);
/* Initialize curl handle */
self->handle = curl_easy_init();
if (self->handle == NULL)
goto error;
res = util_curl_init(self);
if (res < 0)
goto error;
/* Success - return new object */
return self;
error:
Py_DECREF(self); /* this also closes self->handle */
PyErr_SetString(ErrorObject, "initializing curl failed");
return NULL;
}
/* util function shared by close() and clear() */
PYCURL_INTERNAL void
util_curl_xdecref(CurlObject *self, int flags, CURL *handle)
{
if (flags & PYCURL_MEMGROUP_ATTRDICT) {
/* Decrement refcount for attributes dictionary. */
Py_CLEAR(self->dict);
}
if (flags & PYCURL_MEMGROUP_MULTI) {
/* 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. */
(void) curl_multi_remove_handle(multi_stack->multi_handle, handle);
}
Py_DECREF(multi_stack);
}
}
if (flags & PYCURL_MEMGROUP_CALLBACK) {
/* Decrement refcount for python callbacks. */
Py_CLEAR(self->w_cb);
Py_CLEAR(self->h_cb);
Py_CLEAR(self->r_cb);
Py_CLEAR(self->pro_cb);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
Py_CLEAR(self->xferinfo_cb);
#endif
Py_CLEAR(self->debug_cb);
Py_CLEAR(self->ioctl_cb);
Py_CLEAR(self->seek_cb);
Py_CLEAR(self->opensocket_cb);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
Py_CLEAR(self->closesocket_cb);
#endif
Py_CLEAR(self->sockopt_cb);
Py_CLEAR(self->ssh_key_cb);
}
if (flags & PYCURL_MEMGROUP_FILE) {
/* Decrement refcount for python file objects. */
Py_CLEAR(self->readdata_fp);
Py_CLEAR(self->writedata_fp);
Py_CLEAR(self->writeheader_fp);
}
if (flags & PYCURL_MEMGROUP_POSTFIELDS) {
/* Decrement refcount for postfields object */
Py_CLEAR(self->postfields_obj);
}
if (flags & PYCURL_MEMGROUP_SHARE) {
/* Decrement refcount for share objects. */
if (self->share != NULL) {
CurlShareObject *share = self->share;
self->share = NULL;
if (share->share_handle != NULL && handle != NULL) {
curl_easy_setopt(handle, CURLOPT_SHARE, NULL);
}
Py_DECREF(share);
}
}
if (flags & PYCURL_MEMGROUP_HTTPPOST) {
/* Decrement refcounts for httppost related references. */
Py_CLEAR(self->httppost_ref_list);
}
if (flags & PYCURL_MEMGROUP_CACERTS) {
/* Decrement refcounts for ca certs related references. */
Py_CLEAR(self->ca_certs_obj);
}
}
static void
util_curl_close(CurlObject *self)
{
CURL *handle;
/* 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);
handle = self->handle;
self->handle = NULL;
if (handle == NULL) {
/* Some paranoia assertions just to make sure the object
* deallocation problem is finally really fixed... */
#ifdef WITH_THREAD
assert(self->state == NULL);
#endif
assert(self->multi_stack == NULL);
assert(self->share == NULL);
return; /* already closed */
}
#ifdef WITH_THREAD
self->state = NULL;
#endif
/* Decref multi stuff which uses this handle */
util_curl_xdecref(self, PYCURL_MEMGROUP_MULTI, handle);
/* Decref share which uses this handle */
util_curl_xdecref(self, PYCURL_MEMGROUP_SHARE, handle);
/* Cleanup curl handle - must be done without the gil */
Py_BEGIN_ALLOW_THREADS
curl_easy_cleanup(handle);
Py_END_ALLOW_THREADS
handle = NULL;
/* Decref easy related objects */
util_curl_xdecref(self, PYCURL_MEMGROUP_EASY, handle);
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
}
PYCURL_INTERNAL void
do_curl_dealloc(CurlObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_SAFE_BEGIN(self);
Py_CLEAR(self->dict);
util_curl_close(self);
Curl_Type.tp_free(self);
Py_TRASHCAN_SAFE_END(self);
}
static PyObject *
do_curl_close(CurlObject *self)
{
if (check_curl_state(self, 2, "close") != 0) {
return NULL;
}
util_curl_close(self);
Py_RETURN_NONE;
}
/* --------------- GC support --------------- */
/* Drop references that may have created reference cycles. */
PYCURL_INTERNAL int
do_curl_clear(CurlObject *self)
{
#ifdef WITH_THREAD
assert(pycurl_get_thread_state(self) == NULL);
#endif
util_curl_xdecref(self, PYCURL_MEMGROUP_ALL, self->handle);
return 0;
}
/* Traverse all refcounted objects. */
PYCURL_INTERNAL int
do_curl_traverse(CurlObject *self, visitproc visit, void *arg)
{
int err;
#undef VISIT
#define VISIT(v) if ((v) != NULL && ((err = visit(v, arg)) != 0)) return err
VISIT(self->dict);
VISIT((PyObject *) self->multi_stack);
VISIT((PyObject *) self->share);
VISIT(self->w_cb);
VISIT(self->h_cb);
VISIT(self->r_cb);
VISIT(self->pro_cb);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 32, 0)
VISIT(self->xferinfo_cb);
#endif
VISIT(self->debug_cb);
VISIT(self->ioctl_cb);
VISIT(self->seek_cb);
VISIT(self->opensocket_cb);
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 21, 7)
VISIT(self->closesocket_cb);
#endif
VISIT(self->sockopt_cb);
VISIT(self->ssh_key_cb);
VISIT(self->readdata_fp);
VISIT(self->writedata_fp);
VISIT(self->writeheader_fp);
VISIT(self->postfields_obj);
VISIT(self->ca_certs_obj);
return 0;
#undef VISIT
}
/* ------------------------ reset ------------------------ */
static PyObject*
do_curl_reset(CurlObject *self)
{
int res;
curl_easy_reset(self->handle);
/* 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 */
PyErr_SetString(ErrorObject, "resetting curl failed");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *do_curl_getstate(CurlObject *self)
{
PyErr_SetString(PyExc_TypeError, "Curl objects do not support serialization");
return NULL;
}
static PyObject *do_curl_setstate(CurlObject *self, PyObject *args)
{
PyErr_SetString(PyExc_TypeError, "Curl objects do not support deserialization");
return NULL;
}
/*************************************************************************
// type definitions
**************************************************************************/
/* --------------- methods --------------- */
PYCURL_INTERNAL PyMethodDef curlobject_methods[] = {
{"close", (PyCFunction)do_curl_close, METH_NOARGS, curl_close_doc},
{"errstr", (PyCFunction)do_curl_errstr, METH_NOARGS, curl_errstr_doc},
{"errstr_raw", (PyCFunction)do_curl_errstr_raw, METH_NOARGS, curl_errstr_raw_doc},
{"getinfo", (PyCFunction)do_curl_getinfo, METH_VARARGS, curl_getinfo_doc},
{"getinfo_raw", (PyCFunction)do_curl_getinfo_raw, METH_VARARGS, curl_getinfo_raw_doc},
{"pause", (PyCFunction)do_curl_pause, METH_VARARGS, curl_pause_doc},
{"perform", (PyCFunction)do_curl_perform, METH_NOARGS, curl_perform_doc},
{"perform_rb", (PyCFunction)do_curl_perform_rb, METH_NOARGS, curl_perform_rb_doc},
{"perform_rs", (PyCFunction)do_curl_perform_rs, METH_NOARGS, curl_perform_rs_doc},
{"setopt", (PyCFunction)do_curl_setopt, METH_VARARGS, curl_setopt_doc},
{"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},
#if defined(HAVE_CURL_OPENSSL)
{"set_ca_certs", (PyCFunction)do_curl_set_ca_certs, METH_VARARGS, curl_set_ca_certs_doc},
#endif
{"__getstate__", (PyCFunction)do_curl_getstate, METH_NOARGS, NULL},
{"__setstate__", (PyCFunction)do_curl_setstate, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
/* --------------- setattr/getattr --------------- */
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_getattro(PyObject *o, PyObject *n)
{
PyObject *v = PyObject_GenericGetAttr(o, n);
if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
{
PyErr_Clear();
v = my_getattro(o, n, ((CurlObject *)o)->dict,
curlobject_constants, curlobject_methods);
}
return v;
}
PYCURL_INTERNAL int
do_curl_setattro(PyObject *o, PyObject *name, PyObject *v)
{
assert_curl_state((CurlObject *)o);
return my_setattro(&((CurlObject *)o)->dict, name, v);
}
#else /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyObject *
do_curl_getattr(CurlObject *co, char *name)
{
assert_curl_state(co);
return my_getattr((PyObject *)co, name, co->dict,
curlobject_constants, curlobject_methods);
}
PYCURL_INTERNAL int
do_curl_setattr(CurlObject *co, char *name, PyObject *v)
{
assert_curl_state(co);
return my_setattr(&co->dict, name, v);
}
#endif /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyTypeObject Curl_Type = {
#if PY_MAJOR_VERSION >= 3
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
#endif
"pycurl.Curl", /* tp_name */
sizeof(CurlObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)do_curl_dealloc, /* tp_dealloc */
0, /* tp_print */
#if PY_MAJOR_VERSION >= 3
0, /* tp_getattr */
0, /* tp_setattr */
#else
(getattrfunc)do_curl_getattr, /* tp_getattr */
(setattrfunc)do_curl_setattr, /* tp_setattr */
#endif
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
#if PY_MAJOR_VERSION >= 3
(getattrofunc)do_curl_getattro, /* tp_getattro */
(setattrofunc)do_curl_setattro, /* tp_setattro */
#else
0, /* tp_getattro */
0, /* tp_setattro */
#endif
0, /* tp_as_buffer */
PYCURL_TYPE_FLAGS, /* tp_flags */
curl_doc, /* tp_doc */
(traverseproc)do_curl_traverse, /* tp_traverse */
(inquiry)do_curl_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(CurlObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
curlobject_methods, /* 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 */
PyType_GenericAlloc, /* tp_alloc */
(newfunc)do_curl_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/share.c 0000644 0001750 0001750 00000022354 13300711050 014340 0 ustar me me 0000000 0000000 #include "pycurl.h"
#include "docstrings.h"
/*************************************************************************
// static utility functions
**************************************************************************/
/* assert some CurlShareObject invariants */
static void
assert_share_state(const CurlShareObject *self)
{
assert(self != NULL);
assert(Py_TYPE(self) == p_CurlShare_Type);
#ifdef WITH_THREAD
assert(self->lock != NULL);
#endif
}
static int
check_share_state(const CurlShareObject *self, int flags, const char *name)
{
assert_share_state(self);
return 0;
}
/* constructor */
PYCURL_INTERNAL CurlShareObject *
do_share_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
int res;
CurlShareObject *self;
#ifdef WITH_THREAD
const curl_lock_function lock_cb = share_lock_callback;
const curl_unlock_function unlock_cb = share_unlock_callback;
#endif
int *ptr;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
return NULL;
}
/* Allocate python curl-share object */
self = (CurlShareObject *) subtype->tp_alloc(subtype, 0);
if (!self) {
return NULL;
}
/* tp_alloc is expected to return zeroed memory */
for (ptr = (int *) &self->dict;
ptr < (int *) (((char *) self) + sizeof(CurlShareObject));
++ptr) {
assert(*ptr == 0);
}
#ifdef WITH_THREAD
self->lock = share_lock_new();
assert(self->lock != NULL);
#endif
/* Allocate libcurl share handle */
self->share_handle = curl_share_init();
if (self->share_handle == NULL) {
Py_DECREF(self);
PyErr_SetString(ErrorObject, "initializing curl-share failed");
return NULL;
}
#ifdef WITH_THREAD
/* Set locking functions and data */
res = curl_share_setopt(self->share_handle, CURLSHOPT_LOCKFUNC, lock_cb);
assert(res == CURLE_OK);
res = curl_share_setopt(self->share_handle, CURLSHOPT_USERDATA, self);
assert(res == CURLE_OK);
res = curl_share_setopt(self->share_handle, CURLSHOPT_UNLOCKFUNC, unlock_cb);
assert(res == CURLE_OK);
#endif
return self;
}
PYCURL_INTERNAL int
do_share_traverse(CurlShareObject *self, visitproc visit, void *arg)
{
int err;
#undef VISIT
#define VISIT(v) if ((v) != NULL && ((err = visit(v, arg)) != 0)) return err
VISIT(self->dict);
return 0;
#undef VISIT
}
/* Drop references that may have created reference cycles. */
PYCURL_INTERNAL int
do_share_clear(CurlShareObject *self)
{
Py_CLEAR(self->dict);
return 0;
}
static void
util_share_close(CurlShareObject *self){
if (self->share_handle != NULL) {
CURLSH *share_handle = self->share_handle;
self->share_handle = NULL;
curl_share_cleanup(share_handle);
}
}
PYCURL_INTERNAL void
do_share_dealloc(CurlShareObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_SAFE_BEGIN(self);
Py_CLEAR(self->dict);
util_share_close(self);
#ifdef WITH_THREAD
share_lock_destroy(self->lock);
#endif
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
CurlShare_Type.tp_free(self);
Py_TRASHCAN_SAFE_END(self);
}
static PyObject *
do_share_close(CurlShareObject *self)
{
if (check_share_state(self, 2, "close") != 0) {
return NULL;
}
util_share_close(self);
Py_RETURN_NONE;
}
/* setopt, unsetopt*/
/* --------------- unsetopt/setopt/getinfo --------------- */
static PyObject *
do_curlshare_setopt(CurlShareObject *self, PyObject *args)
{
int option;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO:setopt", &option, &obj))
return NULL;
if (check_share_state(self, 1 | 2, "sharesetopt") != 0)
return NULL;
/* early checks of option value */
if (option <= 0)
goto error;
if (option >= (int)CURLOPTTYPE_OFF_T + OPTIONS_SIZE)
goto error;
if (option % 10000 >= OPTIONS_SIZE)
goto error;
#if 0 /* XXX - should we ??? */
/* Handle the case of None */
if (obj == Py_None) {
return util_curl_unsetopt(self, option);
}
#endif
/* Handle the case of integer arguments */
if (PyInt_Check(obj)) {
long d = PyInt_AsLong(obj);
if (d != CURL_LOCK_DATA_COOKIE && d != CURL_LOCK_DATA_DNS && d != CURL_LOCK_DATA_SSL_SESSION) {
goto error;
}
switch(option) {
case CURLSHOPT_SHARE:
case CURLSHOPT_UNSHARE:
curl_share_setopt(self->share_handle, option, d);
break;
default:
PyErr_SetString(PyExc_TypeError, "integers are not supported for this option");
return NULL;
}
Py_RETURN_NONE;
}
/* Failed to match any of the function signatures -- return error */
error:
PyErr_SetString(PyExc_TypeError, "invalid arguments to setopt");
return NULL;
}
static PyObject *do_curlshare_getstate(CurlShareObject *self)
{
PyErr_SetString(PyExc_TypeError, "CurlShare objects do not support serialization");
return NULL;
}
static PyObject *do_curlshare_setstate(CurlShareObject *self, PyObject *args)
{
PyErr_SetString(PyExc_TypeError, "CurlShare objects do not support deserialization");
return NULL;
}
/*************************************************************************
// type definitions
**************************************************************************/
/* --------------- methods --------------- */
PYCURL_INTERNAL PyMethodDef curlshareobject_methods[] = {
{"close", (PyCFunction)do_share_close, METH_NOARGS, share_close_doc},
{"setopt", (PyCFunction)do_curlshare_setopt, METH_VARARGS, share_setopt_doc},
{"__getstate__", (PyCFunction)do_curlshare_getstate, METH_NOARGS, NULL},
{"__setstate__", (PyCFunction)do_curlshare_setstate, METH_VARARGS, NULL},
{NULL, NULL, 0, 0}
};
/* --------------- setattr/getattr --------------- */
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_share_getattro(PyObject *o, PyObject *n)
{
PyObject *v;
assert_share_state((CurlShareObject *)o);
v = PyObject_GenericGetAttr(o, n);
if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
{
PyErr_Clear();
v = my_getattro(o, n, ((CurlShareObject *)o)->dict,
curlshareobject_constants, curlshareobject_methods);
}
return v;
}
PYCURL_INTERNAL int
do_share_setattro(PyObject *o, PyObject *n, PyObject *v)
{
assert_share_state((CurlShareObject *)o);
return my_setattro(&((CurlShareObject *)o)->dict, n, v);
}
#else /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyObject *
do_share_getattr(CurlShareObject *cso, char *name)
{
assert_share_state(cso);
return my_getattr((PyObject *)cso, name, cso->dict,
curlshareobject_constants, curlshareobject_methods);
}
PYCURL_INTERNAL int
do_share_setattr(CurlShareObject *so, char *name, PyObject *v)
{
assert_share_state(so);
return my_setattr(&so->dict, name, v);
}
#endif /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyTypeObject CurlShare_Type = {
#if PY_MAJOR_VERSION >= 3
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
#endif
"pycurl.CurlShare", /* tp_name */
sizeof(CurlShareObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)do_share_dealloc, /* tp_dealloc */
0, /* tp_print */
#if PY_MAJOR_VERSION >= 3
0, /* tp_getattr */
0, /* tp_setattr */
#else
(getattrfunc)do_share_getattr, /* tp_getattr */
(setattrfunc)do_share_setattr, /* tp_setattr */
#endif
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
#if PY_MAJOR_VERSION >= 3
(getattrofunc)do_share_getattro, /* tp_getattro */
(setattrofunc)do_share_setattro, /* tp_setattro */
#else
0, /* tp_getattro */
0, /* tp_setattro */
#endif
0, /* tp_as_buffer */
PYCURL_TYPE_FLAGS, /* tp_flags */
share_doc, /* tp_doc */
(traverseproc)do_share_traverse, /* tp_traverse */
(inquiry)do_share_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(CurlShareObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
curlshareobject_methods, /* 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 */
PyType_GenericAlloc, /* tp_alloc */
(newfunc)do_share_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/stringcompat.c 0000644 0001750 0001750 00000004235 13301165576 015767 0 ustar me me 0000000 0000000 #include "pycurl.h"
/*************************************************************************
// python utility functions
**************************************************************************/
PYCURL_INTERNAL int
PyText_AsStringAndSize(PyObject *obj, char **buffer, Py_ssize_t *length, PyObject **encoded_obj)
{
if (PyByteStr_Check(obj)) {
*encoded_obj = NULL;
return PyByteStr_AsStringAndSize(obj, buffer, length);
} else {
int rv;
assert(PyUnicode_Check(obj));
*encoded_obj = PyUnicode_AsEncodedString(obj, "ascii", "strict");
if (*encoded_obj == NULL) {
return -1;
}
rv = PyByteStr_AsStringAndSize(*encoded_obj, buffer, length);
if (rv != 0) {
/* If we free the object, pointer must be reset to NULL */
Py_CLEAR(*encoded_obj);
}
return rv;
}
}
/* Like PyString_AsString(), but set an exception if the string contains
* embedded NULs. Actually PyString_AsStringAndSize() already does that for
* us if the `len' parameter is NULL - see Objects/stringobject.c.
*/
PYCURL_INTERNAL char *
PyText_AsString_NoNUL(PyObject *obj, PyObject **encoded_obj)
{
char *s = NULL;
Py_ssize_t r;
r = PyText_AsStringAndSize(obj, &s, NULL, encoded_obj);
if (r != 0)
return NULL; /* exception already set */
assert(s != NULL);
return s;
}
/* Returns true if the object is of a type that can be given to
* curl_easy_setopt and such - either a byte string or a Unicode string
* with ASCII code points only.
*/
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL int
PyText_Check(PyObject *o)
{
return PyUnicode_Check(o) || PyBytes_Check(o);
}
#else
PYCURL_INTERNAL int
PyText_Check(PyObject *o)
{
return PyUnicode_Check(o) || PyString_Check(o);
}
#endif
PYCURL_INTERNAL PyObject *
PyText_FromString_Ignore(const char *string)
{
PyObject *v;
#if PY_MAJOR_VERSION >= 3
PyObject *u;
v = Py_BuildValue("y", string);
if (v == NULL) {
return NULL;
}
u = PyUnicode_FromEncodedObject(v, NULL, "replace");
Py_DECREF(v);
return u;
#else
v = Py_BuildValue("s", string);
return v;
#endif
}
pycurl-7.43.0.2/src/easyinfo.c 0000644 0001750 0001750 00000023461 13301173520 015060 0 ustar me me 0000000 0000000 #include "pycurl.h"
/* Convert a curl slist (a list of strings) to a Python list.
* In case of error return NULL with an exception set.
*/
static PyObject *convert_slist(struct curl_slist *slist, int free_flags)
{
PyObject *ret = NULL;
struct curl_slist *slist_start = slist;
ret = PyList_New((Py_ssize_t)0);
if (ret == NULL) goto error;
for ( ; slist != NULL; slist = slist->next) {
PyObject *v = NULL;
if (slist->data == NULL) {
v = Py_None; Py_INCREF(v);
} else {
v = PyByteStr_FromString(slist->data);
}
if (v == NULL || PyList_Append(ret, v) != 0) {
Py_XDECREF(v);
goto error;
}
Py_DECREF(v);
}
if ((free_flags & 1) && slist_start)
curl_slist_free_all(slist_start);
return ret;
error:
Py_XDECREF(ret);
if ((free_flags & 2) && slist_start)
curl_slist_free_all(slist_start);
return NULL;
}
#ifdef HAVE_CURLOPT_CERTINFO
/* Convert a struct curl_certinfo into a Python data structure.
* In case of error return NULL with an exception set.
*/
static PyObject *convert_certinfo(struct curl_certinfo *cinfo, int decode)
{
PyObject *certs;
int cert_index;
if (!cinfo)
Py_RETURN_NONE;
certs = PyList_New((Py_ssize_t)(cinfo->num_of_certs));
if (!certs)
return NULL;
for (cert_index = 0; cert_index < cinfo->num_of_certs; cert_index ++) {
struct curl_slist *fields = cinfo->certinfo[cert_index];
struct curl_slist *field_cursor;
int field_count, field_index;
PyObject *cert;
field_count = 0;
field_cursor = fields;
while (field_cursor != NULL) {
field_cursor = field_cursor->next;
field_count ++;
}
cert = PyTuple_New((Py_ssize_t)field_count);
if (!cert)
goto error;
PyList_SetItem(certs, cert_index, cert); /* Eats the ref from New() */
for(field_index = 0, field_cursor = fields;
field_cursor != NULL;
field_index ++, field_cursor = field_cursor->next) {
const char *field = field_cursor->data;
PyObject *field_tuple;
if (!field) {
field_tuple = Py_None; Py_INCREF(field_tuple);
} else {
const char *sep = strchr(field, ':');
if (!sep) {
if (decode) {
field_tuple = PyText_FromString(field);
} else {
field_tuple = PyByteStr_FromString(field);
}
} else {
/* XXX check */
if (decode) {
field_tuple = Py_BuildValue("s#s", field, (int)(sep - field), sep+1);
} else {
#if PY_MAJOR_VERSION >= 3
field_tuple = Py_BuildValue("y#y", field, (int)(sep - field), sep+1);
#else
field_tuple = Py_BuildValue("s#s", field, (int)(sep - field), sep+1);
#endif
}
}
if (!field_tuple)
goto error;
}
PyTuple_SET_ITEM(cert, field_index, field_tuple); /* Eats the ref */
}
}
return certs;
error:
Py_DECREF(certs);
return NULL;
}
#endif
PYCURL_INTERNAL PyObject *
do_curl_getinfo_raw(CurlObject *self, PyObject *args)
{
int option;
int res;
if (!PyArg_ParseTuple(args, "i:getinfo_raw", &option)) {
return NULL;
}
if (check_curl_state(self, 1 | 2, "getinfo") != 0) {
return NULL;
}
switch (option) {
case CURLINFO_FILETIME:
case CURLINFO_HEADER_SIZE:
case CURLINFO_RESPONSE_CODE:
case CURLINFO_REDIRECT_COUNT:
case CURLINFO_REQUEST_SIZE:
case CURLINFO_SSL_VERIFYRESULT:
case CURLINFO_HTTP_CONNECTCODE:
case CURLINFO_HTTPAUTH_AVAIL:
case CURLINFO_PROXYAUTH_AVAIL:
case CURLINFO_OS_ERRNO:
case CURLINFO_NUM_CONNECTS:
case CURLINFO_LASTSOCKET:
#ifdef HAVE_CURLINFO_LOCAL_PORT
case CURLINFO_LOCAL_PORT:
#endif
#ifdef HAVE_CURLINFO_PRIMARY_PORT
case CURLINFO_PRIMARY_PORT:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
case CURLINFO_RTSP_CLIENT_CSEQ:
case CURLINFO_RTSP_SERVER_CSEQ:
case CURLINFO_RTSP_CSEQ_RECV:
#endif
#ifdef HAVE_CURLINFO_HTTP_VERSION
case CURLINFO_HTTP_VERSION:
#endif
{
/* Return PyInt as result */
long l_res = -1;
res = curl_easy_getinfo(self->handle, (CURLINFO)option, &l_res);
/* Check for errors and return result */
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
return PyInt_FromLong(l_res);
}
case CURLINFO_CONTENT_TYPE:
case CURLINFO_EFFECTIVE_URL:
case CURLINFO_FTP_ENTRY_PATH:
case CURLINFO_REDIRECT_URL:
case CURLINFO_PRIMARY_IP:
#ifdef HAVE_CURLINFO_LOCAL_IP
case CURLINFO_LOCAL_IP:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
case CURLINFO_RTSP_SESSION_ID:
#endif
{
/* Return PyString as result */
char *s_res = NULL;
res = curl_easy_getinfo(self->handle, (CURLINFO)option, &s_res);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
/* If the resulting string is NULL, return None */
if (s_res == NULL) {
Py_RETURN_NONE;
}
return PyByteStr_FromString(s_res);
}
case CURLINFO_CONNECT_TIME:
case CURLINFO_APPCONNECT_TIME:
case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
case CURLINFO_CONTENT_LENGTH_UPLOAD:
case CURLINFO_NAMELOOKUP_TIME:
case CURLINFO_PRETRANSFER_TIME:
case CURLINFO_REDIRECT_TIME:
case CURLINFO_SIZE_DOWNLOAD:
case CURLINFO_SIZE_UPLOAD:
case CURLINFO_SPEED_DOWNLOAD:
case CURLINFO_SPEED_UPLOAD:
case CURLINFO_STARTTRANSFER_TIME:
case CURLINFO_TOTAL_TIME:
{
/* Return PyFloat as result */
double d_res = 0.0;
res = curl_easy_getinfo(self->handle, (CURLINFO)option, &d_res);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
return PyFloat_FromDouble(d_res);
}
case CURLINFO_SSL_ENGINES:
case CURLINFO_COOKIELIST:
{
/* Return a list of strings */
struct curl_slist *slist = NULL;
res = curl_easy_getinfo(self->handle, (CURLINFO)option, &slist);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
}
return convert_slist(slist, 1 | 2);
}
#ifdef HAVE_CURLOPT_CERTINFO
case CURLINFO_CERTINFO:
{
/* Return a list of lists of 2-tuples */
struct curl_certinfo *clist = NULL;
res = curl_easy_getinfo(self->handle, CURLINFO_CERTINFO, &clist);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
} else {
return convert_certinfo(clist, 0);
}
}
#endif
}
/* Got wrong option on the method call */
PyErr_SetString(PyExc_ValueError, "invalid argument to getinfo");
return NULL;
}
#if PY_MAJOR_VERSION >= 3
static PyObject *
decode_string_list(PyObject *list)
{
PyObject *decoded_list = NULL;
Py_ssize_t size = PyList_Size(list);
int i;
decoded_list = PyList_New(size);
if (decoded_list == NULL) {
return NULL;
}
for (i = 0; i < size; ++i) {
PyObject *decoded_item = PyUnicode_FromEncodedObject(
PyList_GET_ITEM(list, i),
NULL,
NULL);
if (decoded_item == NULL) {
goto err;
}
}
return decoded_list;
err:
Py_DECREF(decoded_list);
return NULL;
}
PYCURL_INTERNAL PyObject *
do_curl_getinfo(CurlObject *self, PyObject *args)
{
int option, res;
PyObject *rv;
if (!PyArg_ParseTuple(args, "i:getinfo", &option)) {
return NULL;
}
#ifdef HAVE_CURLOPT_CERTINFO
if (option == CURLINFO_CERTINFO) {
/* Return a list of lists of 2-tuples */
struct curl_certinfo *clist = NULL;
res = curl_easy_getinfo(self->handle, CURLINFO_CERTINFO, &clist);
if (res != CURLE_OK) {
CURLERROR_RETVAL();
} else {
return convert_certinfo(clist, 1);
}
}
#endif
rv = do_curl_getinfo_raw(self, args);
if (rv == NULL) {
return rv;
}
switch (option) {
case CURLINFO_CONTENT_TYPE:
case CURLINFO_EFFECTIVE_URL:
case CURLINFO_FTP_ENTRY_PATH:
case CURLINFO_REDIRECT_URL:
case CURLINFO_PRIMARY_IP:
#ifdef HAVE_CURLINFO_LOCAL_IP
case CURLINFO_LOCAL_IP:
#endif
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 20, 0)
case CURLINFO_RTSP_SESSION_ID:
#endif
{
PyObject *decoded;
// Decode bytes into a Unicode string using default encoding
decoded = PyUnicode_FromEncodedObject(rv, NULL, NULL);
// success and failure paths both need to free bytes object
Py_DECREF(rv);
return decoded;
}
case CURLINFO_SSL_ENGINES:
case CURLINFO_COOKIELIST:
{
PyObject *decoded = decode_string_list(rv);
Py_DECREF(rv);
return decoded;
}
default:
return rv;
}
}
#endif
PYCURL_INTERNAL PyObject *
do_curl_errstr(CurlObject *self)
{
if (check_curl_state(self, 1 | 2, "errstr") != 0) {
return NULL;
}
self->error[sizeof(self->error) - 1] = 0;
return PyText_FromString(self->error);
}
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_curl_errstr_raw(CurlObject *self)
{
if (check_curl_state(self, 1 | 2, "errstr") != 0) {
return NULL;
}
self->error[sizeof(self->error) - 1] = 0;
return PyByteStr_FromString(self->error);
}
#endif
pycurl-7.43.0.2/src/multi.c 0000644 0001750 0001750 00000071042 13300711050 014366 0 ustar me me 0000000 0000000 #include "pycurl.h"
#include "docstrings.h"
/*************************************************************************
// static utility functions
**************************************************************************/
/* assert some CurlMultiObject invariants */
static void
assert_multi_state(const CurlMultiObject *self)
{
assert(self != NULL);
assert(Py_TYPE(self) == p_CurlMulti_Type);
#ifdef WITH_THREAD
if (self->state != NULL) {
assert(self->multi_handle != NULL);
}
#endif
}
static int
check_multi_state(const CurlMultiObject *self, int flags, const char *name)
{
assert_multi_state(self);
if ((flags & 1) && self->multi_handle == NULL) {
PyErr_Format(ErrorObject, "cannot invoke %s() - no multi handle", name);
return -1;
}
#ifdef WITH_THREAD
if ((flags & 2) && self->state != NULL) {
PyErr_Format(ErrorObject, "cannot invoke %s() - multi_perform() is currently running", name);
return -1;
}
#endif
return 0;
}
/*************************************************************************
// CurlMultiObject
**************************************************************************/
/* --------------- construct/destruct (i.e. open/close) --------------- */
/* constructor */
PYCURL_INTERNAL CurlMultiObject *
do_multi_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds)
{
CurlMultiObject *self;
int *ptr;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", empty_keywords)) {
return NULL;
}
/* Allocate python curl-multi object */
self = (CurlMultiObject *) p_CurlMulti_Type->tp_alloc(p_CurlMulti_Type, 0);
if (!self) {
return NULL;
}
/* tp_alloc is expected to return zeroed memory */
for (ptr = (int *) &self->dict;
ptr < (int *) (((char *) self) + sizeof(CurlMultiObject));
++ptr)
assert(*ptr == 0);
self->easy_object_dict = PyDict_New();
if (self->easy_object_dict == NULL) {
Py_DECREF(self);
return NULL;
}
/* Allocate libcurl multi handle */
self->multi_handle = curl_multi_init();
if (self->multi_handle == NULL) {
Py_DECREF(self);
PyErr_SetString(ErrorObject, "initializing curl-multi failed");
return NULL;
}
return self;
}
static void
util_multi_close(CurlMultiObject *self)
{
assert(self != NULL);
#ifdef WITH_THREAD
self->state = NULL;
#endif
if (self->multi_handle != NULL) {
CURLM *multi_handle = self->multi_handle;
self->multi_handle = NULL;
curl_multi_cleanup(multi_handle);
}
}
static void
util_multi_xdecref(CurlMultiObject *self)
{
Py_CLEAR(self->easy_object_dict);
Py_CLEAR(self->dict);
Py_CLEAR(self->t_cb);
Py_CLEAR(self->s_cb);
}
PYCURL_INTERNAL void
do_multi_dealloc(CurlMultiObject *self)
{
PyObject_GC_UnTrack(self);
Py_TRASHCAN_SAFE_BEGIN(self);
util_multi_xdecref(self);
util_multi_close(self);
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
CurlMulti_Type.tp_free(self);
Py_TRASHCAN_SAFE_END(self);
}
static PyObject *
do_multi_close(CurlMultiObject *self)
{
if (check_multi_state(self, 2, "close") != 0) {
return NULL;
}
util_multi_close(self);
Py_RETURN_NONE;
}
/* --------------- GC support --------------- */
/* Drop references that may have created reference cycles. */
PYCURL_INTERNAL int
do_multi_clear(CurlMultiObject *self)
{
util_multi_xdecref(self);
return 0;
}
PYCURL_INTERNAL int
do_multi_traverse(CurlMultiObject *self, visitproc visit, void *arg)
{
int err;
#undef VISIT
#define VISIT(v) if ((v) != NULL && ((err = visit(v, arg)) != 0)) return err
VISIT(self->dict);
VISIT(self->easy_object_dict);
return 0;
#undef VISIT
}
/* --------------- setopt --------------- */
static int
multi_socket_callback(CURL *easy,
curl_socket_t s,
int what,
void *userp,
void *socketp)
{
CurlMultiObject *self;
PyObject *arglist;
PyObject *result = NULL;
PYCURL_DECLARE_THREAD_STATE;
/* acquire thread */
self = (CurlMultiObject *)userp;
if (!PYCURL_ACQUIRE_THREAD_MULTI())
return 0;
/* check args */
if (self->s_cb == NULL)
goto silent_error;
if (socketp == NULL) {
Py_INCREF(Py_None);
socketp = Py_None;
}
/* run callback */
arglist = Py_BuildValue("(iiOO)", what, s, userp, (PyObject *)socketp);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->s_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* return values from socket callbacks should be ignored */
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return 0;
verbose_error:
PyErr_Print();
goto silent_error;
return 0;
}
static int
multi_timer_callback(CURLM *multi,
long timeout_ms,
void *userp)
{
CurlMultiObject *self;
PyObject *arglist;
PyObject *result = NULL;
int ret = 0; /* always success */
PYCURL_DECLARE_THREAD_STATE;
UNUSED(multi);
/* acquire thread */
self = (CurlMultiObject *)userp;
if (!PYCURL_ACQUIRE_THREAD_MULTI())
return ret;
/* check args */
if (self->t_cb == NULL)
goto silent_error;
/* run callback */
arglist = Py_BuildValue("(i)", timeout_ms);
if (arglist == NULL)
goto verbose_error;
result = PyEval_CallObject(self->t_cb, arglist);
Py_DECREF(arglist);
if (result == NULL)
goto verbose_error;
/* return values from timer callbacks should be ignored */
silent_error:
Py_XDECREF(result);
PYCURL_RELEASE_THREAD();
return ret;
verbose_error:
PyErr_Print();
goto silent_error;
return 0;
}
static PyObject *
do_multi_setopt_int(CurlMultiObject *self, int option, PyObject *obj)
{
long d = PyInt_AsLong(obj);
switch(option) {
case CURLMOPT_MAXCONNECTS:
case CURLMOPT_PIPELINING:
#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
case CURLMOPT_MAX_HOST_CONNECTIONS:
case CURLMOPT_MAX_TOTAL_CONNECTIONS:
case CURLMOPT_MAX_PIPELINE_LENGTH:
case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
#endif
curl_multi_setopt(self->multi_handle, option, d);
break;
default:
PyErr_SetString(PyExc_TypeError, "integers are not supported for this option");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
do_multi_setopt_charpp(CurlMultiObject *self, int option, int which, PyObject *obj)
{
Py_ssize_t len, i;
int res;
static const char *empty_list[] = { NULL };
char **list = NULL;
PyObject **encoded_objs = NULL;
PyObject *encoded_obj = NULL;
char *encoded_str;
PyObject *rv = NULL;
len = PyListOrTuple_Size(obj, which);
if (len == 0) {
res = curl_multi_setopt(self->multi_handle, option, empty_list);
if (res != CURLE_OK) {
CURLERROR_RETVAL_MULTI_DONE();
}
Py_RETURN_NONE;
}
/* add NULL terminator as the last list item */
list = PyMem_New(char *, len+1);
if (list == NULL) {
PyErr_NoMemory();
return NULL;
}
/* no need for the NULL terminator here */
encoded_objs = PyMem_New(PyObject *, len);
if (encoded_objs == NULL) {
PyErr_NoMemory();
goto done;
}
memset(encoded_objs, 0, sizeof(PyObject *) * len);
for (i = 0; i < len; i++) {
PyObject *listitem = PyListOrTuple_GetItem(obj, i, which);
if (!PyText_Check(listitem)) {
PyErr_SetString(ErrorObject, "list/tuple items must be strings");
goto done;
}
encoded_str = PyText_AsString_NoNUL(listitem, &encoded_obj);
if (encoded_str == NULL) {
goto done;
}
list[i] = encoded_str;
encoded_objs[i] = encoded_obj;
}
list[len] = NULL;
res = curl_multi_setopt(self->multi_handle, option, list);
if (res != CURLE_OK) {
rv = NULL;
CURLERROR_RETVAL_MULTI_DONE();
}
rv = Py_None;
done:
if (encoded_objs) {
for (i = 0; i < len; i++) {
Py_XDECREF(encoded_objs[i]);
}
PyMem_Free(encoded_objs);
}
PyMem_Free(list);
return rv;
}
static PyObject *
do_multi_setopt_list(CurlMultiObject *self, int option, int which, PyObject *obj)
{
switch(option) {
#ifdef HAVE_CURL_7_30_0_PIPELINE_OPTS
case CURLMOPT_PIPELINING_SITE_BL:
case CURLMOPT_PIPELINING_SERVER_BL:
#endif
return do_multi_setopt_charpp(self, option, which, obj);
break;
default:
PyErr_SetString(PyExc_TypeError, "lists/tuples are not supported for this option");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
do_multi_setopt_callable(CurlMultiObject *self, int option, PyObject *obj)
{
/* We use function types here to make sure that our callback
* definitions exactly match the interface.
*/
const curl_multi_timer_callback t_cb = multi_timer_callback;
const curl_socket_callback s_cb = multi_socket_callback;
switch(option) {
case CURLMOPT_SOCKETFUNCTION:
curl_multi_setopt(self->multi_handle, CURLMOPT_SOCKETFUNCTION, s_cb);
curl_multi_setopt(self->multi_handle, CURLMOPT_SOCKETDATA, self);
Py_INCREF(obj);
self->s_cb = obj;
break;
case CURLMOPT_TIMERFUNCTION:
curl_multi_setopt(self->multi_handle, CURLMOPT_TIMERFUNCTION, t_cb);
curl_multi_setopt(self->multi_handle, CURLMOPT_TIMERDATA, self);
Py_INCREF(obj);
self->t_cb = obj;
break;
default:
PyErr_SetString(PyExc_TypeError, "callables are not supported for this option");
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
do_multi_setopt(CurlMultiObject *self, PyObject *args)
{
int option, which;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO:setopt", &option, &obj))
return NULL;
if (check_multi_state(self, 1 | 2, "setopt") != 0)
return NULL;
/* Early checks of option value */
if (option <= 0)
goto error;
if (option >= (int)CURLOPTTYPE_OFF_T + MOPTIONS_SIZE)
goto error;
if (option % 10000 >= MOPTIONS_SIZE)
goto error;
/* Handle the case of integer arguments */
if (PyInt_Check(obj)) {
return do_multi_setopt_int(self, option, obj);
}
/* Handle the case of list or tuple objects */
which = PyListOrTuple_Check(obj);
if (which) {
return do_multi_setopt_list(self, option, which, obj);
}
if (PyFunction_Check(obj) || PyCFunction_Check(obj) ||
PyCallable_Check(obj) || PyMethod_Check(obj)) {
return do_multi_setopt_callable(self, option, obj);
}
/* Failed to match any of the function signatures -- return error */
error:
PyErr_SetString(PyExc_TypeError, "invalid arguments to setopt");
return NULL;
}
/* --------------- timeout --------------- */
static PyObject *
do_multi_timeout(CurlMultiObject *self)
{
CURLMcode res;
long timeout;
if (check_multi_state(self, 1 | 2, "timeout") != 0) {
return NULL;
}
res = curl_multi_timeout(self->multi_handle, &timeout);
if (res != CURLM_OK) {
CURLERROR_MSG("timeout failed");
}
/* Return number of millisecs until timeout */
return Py_BuildValue("l", timeout);
}
/* --------------- assign --------------- */
static PyObject *
do_multi_assign(CurlMultiObject *self, PyObject *args)
{
CURLMcode res;
curl_socket_t socket;
PyObject *obj;
if (!PyArg_ParseTuple(args, "iO:assign", &socket, &obj))
return NULL;
if (check_multi_state(self, 1 | 2, "assign") != 0) {
return NULL;
}
Py_INCREF(obj);
res = curl_multi_assign(self->multi_handle, socket, obj);
if (res != CURLM_OK) {
CURLERROR_MSG("assign failed");
}
Py_RETURN_NONE;
}
/* --------------- socket_action --------------- */
static PyObject *
do_multi_socket_action(CurlMultiObject *self, PyObject *args)
{
CURLMcode res;
curl_socket_t socket;
int ev_bitmask;
int running = -1;
if (!PyArg_ParseTuple(args, "ii:socket_action", &socket, &ev_bitmask))
return NULL;
if (check_multi_state(self, 1 | 2, "socket_action") != 0) {
return NULL;
}
PYCURL_BEGIN_ALLOW_THREADS
res = curl_multi_socket_action(self->multi_handle, socket, ev_bitmask, &running);
PYCURL_END_ALLOW_THREADS
if (res != CURLM_OK) {
CURLERROR_MSG("multi_socket_action failed");
}
/* Return a tuple with the result and the number of running handles */
return Py_BuildValue("(ii)", (int)res, running);
}
/* --------------- socket_all --------------- */
static PyObject *
do_multi_socket_all(CurlMultiObject *self)
{
CURLMcode res;
int running = -1;
if (check_multi_state(self, 1 | 2, "socket_all") != 0) {
return NULL;
}
PYCURL_BEGIN_ALLOW_THREADS
res = curl_multi_socket_all(self->multi_handle, &running);
PYCURL_END_ALLOW_THREADS
/* We assume these errors are ok, otherwise raise exception */
if (res != CURLM_OK && res != CURLM_CALL_MULTI_PERFORM) {
CURLERROR_MSG("perform failed");
}
/* Return a tuple with the result and the number of running handles */
return Py_BuildValue("(ii)", (int)res, running);
}
/* --------------- perform --------------- */
static PyObject *
do_multi_perform(CurlMultiObject *self)
{
CURLMcode res;
int running = -1;
if (check_multi_state(self, 1 | 2, "perform") != 0) {
return NULL;
}
PYCURL_BEGIN_ALLOW_THREADS
res = curl_multi_perform(self->multi_handle, &running);
PYCURL_END_ALLOW_THREADS
/* We assume these errors are ok, otherwise raise exception */
if (res != CURLM_OK && res != CURLM_CALL_MULTI_PERFORM) {
CURLERROR_MSG("perform failed");
}
/* Return a tuple with the result and the number of running handles */
return Py_BuildValue("(ii)", (int)res, running);
}
/* --------------- add_handle/remove_handle --------------- */
/* static utility function */
static int
check_multi_add_remove(const CurlMultiObject *self, const CurlObject *obj)
{
/* check CurlMultiObject status */
assert_multi_state(self);
if (self->multi_handle == NULL) {
PyErr_SetString(ErrorObject, "cannot add/remove handle - multi-stack is closed");
return -1;
}
#ifdef WITH_THREAD
if (self->state != NULL) {
PyErr_SetString(ErrorObject, "cannot add/remove handle - multi_perform() already running");
return -1;
}
#endif
/* check CurlObject status */
assert_curl_state(obj);
#ifdef WITH_THREAD
if (obj->state != NULL) {
PyErr_SetString(ErrorObject, "cannot add/remove handle - perform() of curl object already running");
return -1;
}
#endif
if (obj->multi_stack != NULL && obj->multi_stack != self) {
PyErr_SetString(ErrorObject, "cannot add/remove handle - curl object already on another multi-stack");
return -1;
}
return 0;
}
static PyObject *
do_multi_add_handle(CurlMultiObject *self, PyObject *args)
{
CurlObject *obj;
CURLMcode res;
if (!PyArg_ParseTuple(args, "O!:add_handle", p_Curl_Type, &obj)) {
return NULL;
}
if (check_multi_add_remove(self, obj) != 0) {
return NULL;
}
if (obj->handle == NULL) {
PyErr_SetString(ErrorObject, "curl object already closed");
return NULL;
}
if (obj->multi_stack == self) {
PyErr_SetString(ErrorObject, "curl object already on this multi-stack");
return NULL;
}
PyDict_SetItem(self->easy_object_dict, (PyObject *) obj, Py_True);
assert(obj->multi_stack == NULL);
res = curl_multi_add_handle(self->multi_handle, obj->handle);
if (res != CURLM_OK) {
CURLERROR_MSG("curl_multi_add_handle() failed due to internal errors");
PyDict_DelItem(self->easy_object_dict, (PyObject *) obj);
}
obj->multi_stack = self;
Py_INCREF(self);
Py_RETURN_NONE;
}
static PyObject *
do_multi_remove_handle(CurlMultiObject *self, PyObject *args)
{
CurlObject *obj;
CURLMcode res;
if (!PyArg_ParseTuple(args, "O!:remove_handle", p_Curl_Type, &obj)) {
return NULL;
}
if (check_multi_add_remove(self, obj) != 0) {
return NULL;
}
if (obj->handle == NULL) {
/* CurlObject handle already closed -- ignore */
if (PyDict_GetItem(self->easy_object_dict, (PyObject *) obj)) {
PyDict_DelItem(self->easy_object_dict, (PyObject *) obj);
}
goto done;
}
if (obj->multi_stack != self) {
PyErr_SetString(ErrorObject, "curl object not on this multi-stack");
return NULL;
}
res = curl_multi_remove_handle(self->multi_handle, obj->handle);
if (res == CURLM_OK) {
PyDict_DelItem(self->easy_object_dict, (PyObject *) obj);
// if PyDict_DelItem fails, remove_handle call will also fail.
// but the dictionary should always have our object in it
// hence this failure shouldn't happen unless something unaccounted
// for went wrong
} else {
CURLERROR_MSG("curl_multi_remove_handle() failed due to internal errors");
}
assert(obj->multi_stack == self);
obj->multi_stack = NULL;
Py_DECREF(self);
done:
Py_RETURN_NONE;
}
/* --------------- fdset ---------------------- */
static PyObject *
do_multi_fdset(CurlMultiObject *self)
{
CURLMcode res;
int max_fd = -1, fd;
PyObject *ret = NULL;
PyObject *read_list = NULL, *write_list = NULL, *except_list = NULL;
PyObject *py_fd = NULL;
if (check_multi_state(self, 1 | 2, "fdset") != 0) {
return NULL;
}
/* Clear file descriptor sets */
FD_ZERO(&self->read_fd_set);
FD_ZERO(&self->write_fd_set);
FD_ZERO(&self->exc_fd_set);
/* Don't bother releasing the gil as this is just a data structure operation */
res = curl_multi_fdset(self->multi_handle, &self->read_fd_set,
&self->write_fd_set, &self->exc_fd_set, &max_fd);
if (res != CURLM_OK) {
CURLERROR_MSG("curl_multi_fdset() failed due to internal errors");
}
/* Allocate lists. */
if ((read_list = PyList_New((Py_ssize_t)0)) == NULL) goto error;
if ((write_list = PyList_New((Py_ssize_t)0)) == NULL) goto error;
if ((except_list = PyList_New((Py_ssize_t)0)) == NULL) goto error;
/* Populate lists */
for (fd = 0; fd < max_fd + 1; fd++) {
if (FD_ISSET(fd, &self->read_fd_set)) {
if ((py_fd = PyInt_FromLong((long)fd)) == NULL) goto error;
if (PyList_Append(read_list, py_fd) != 0) goto error;
Py_DECREF(py_fd);
py_fd = NULL;
}
if (FD_ISSET(fd, &self->write_fd_set)) {
if ((py_fd = PyInt_FromLong((long)fd)) == NULL) goto error;
if (PyList_Append(write_list, py_fd) != 0) goto error;
Py_DECREF(py_fd);
py_fd = NULL;
}
if (FD_ISSET(fd, &self->exc_fd_set)) {
if ((py_fd = PyInt_FromLong((long)fd)) == NULL) goto error;
if (PyList_Append(except_list, py_fd) != 0) goto error;
Py_DECREF(py_fd);
py_fd = NULL;
}
}
/* Return a tuple with the 3 lists */
ret = Py_BuildValue("(OOO)", read_list, write_list, except_list);
error:
Py_XDECREF(py_fd);
Py_XDECREF(except_list);
Py_XDECREF(write_list);
Py_XDECREF(read_list);
return ret;
}
/* --------------- info_read --------------- */
static PyObject *
do_multi_info_read(CurlMultiObject *self, PyObject *args)
{
PyObject *ret = NULL;
PyObject *ok_list = NULL, *err_list = NULL;
CURLMsg *msg;
int in_queue = 0, num_results = INT_MAX;
/* Sanity checks */
if (!PyArg_ParseTuple(args, "|i:info_read", &num_results)) {
return NULL;
}
if (num_results <= 0) {
PyErr_SetString(ErrorObject, "argument to info_read must be greater than zero");
return NULL;
}
if (check_multi_state(self, 1 | 2, "info_read") != 0) {
return NULL;
}
if ((ok_list = PyList_New((Py_ssize_t)0)) == NULL) goto error;
if ((err_list = PyList_New((Py_ssize_t)0)) == NULL) goto error;
/* Loop through all messages */
while ((msg = curl_multi_info_read(self->multi_handle, &in_queue)) != NULL) {
CURLcode res;
CurlObject *co = NULL;
/* Check for termination as specified by the user */
if (num_results-- <= 0) {
break;
}
/* Fetch the curl object that corresponds to the curl handle in the message */
res = curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, (char **) &co);
if (res != CURLE_OK || co == NULL) {
Py_DECREF(err_list);
Py_DECREF(ok_list);
CURLERROR_MSG("Unable to fetch curl handle from curl object");
}
assert(Py_TYPE(co) == p_Curl_Type);
if (msg->msg != CURLMSG_DONE) {
/* FIXME: what does this mean ??? */
}
if (msg->data.result == CURLE_OK) {
/* Append curl object to list of objects which succeeded */
if (PyList_Append(ok_list, (PyObject *)co) != 0) {
goto error;
}
}
else {
/* Create a result tuple that will get added to err_list. */
PyObject *v = Py_BuildValue("(Ois)", (PyObject *)co, (int)msg->data.result, co->error);
/* Append curl object to list of objects which failed */
if (v == NULL || PyList_Append(err_list, v) != 0) {
Py_XDECREF(v);
goto error;
}
Py_DECREF(v);
}
}
/* Return (number of queued messages, [ok_objects], [error_objects]) */
ret = Py_BuildValue("(iOO)", in_queue, ok_list, err_list);
error:
Py_XDECREF(err_list);
Py_XDECREF(ok_list);
return ret;
}
/* --------------- select --------------- */
static PyObject *
do_multi_select(CurlMultiObject *self, PyObject *args)
{
int max_fd = -1, n;
double timeout = -1.0;
struct timeval tv, *tvp;
CURLMcode res;
if (!PyArg_ParseTuple(args, "d:select", &timeout)) {
return NULL;
}
if (check_multi_state(self, 1 | 2, "select") != 0) {
return NULL;
}
if (timeout < 0 || timeout >= 365 * 24 * 60 * 60) {
PyErr_SetString(PyExc_OverflowError, "invalid timeout period");
return NULL;
} else {
long seconds = (long)timeout;
timeout = timeout - (double)seconds;
assert(timeout >= 0.0); assert(timeout < 1.0);
tv.tv_sec = seconds;
tv.tv_usec = (long)(timeout*1000000.0);
tvp = &tv;
}
FD_ZERO(&self->read_fd_set);
FD_ZERO(&self->write_fd_set);
FD_ZERO(&self->exc_fd_set);
res = curl_multi_fdset(self->multi_handle, &self->read_fd_set,
&self->write_fd_set, &self->exc_fd_set, &max_fd);
if (res != CURLM_OK) {
CURLERROR_MSG("multi_fdset failed");
}
if (max_fd < 0) {
n = 0;
}
else {
Py_BEGIN_ALLOW_THREADS
n = select(max_fd + 1, &self->read_fd_set, &self->write_fd_set, &self->exc_fd_set, tvp);
Py_END_ALLOW_THREADS
/* info: like Python's socketmodule.c we do not raise an exception
* if select() fails - we'll leave it to the actual libcurl
* socket code to report any errors.
*/
}
return PyInt_FromLong(n);
}
static PyObject *do_curlmulti_getstate(CurlMultiObject *self)
{
PyErr_SetString(PyExc_TypeError, "CurlMulti objects do not support serialization");
return NULL;
}
static PyObject *do_curlmulti_setstate(CurlMultiObject *self, PyObject *args)
{
PyErr_SetString(PyExc_TypeError, "CurlMulti objects do not support deserialization");
return NULL;
}
/*************************************************************************
// type definitions
**************************************************************************/
/* --------------- methods --------------- */
PYCURL_INTERNAL PyMethodDef curlmultiobject_methods[] = {
{"add_handle", (PyCFunction)do_multi_add_handle, METH_VARARGS, multi_add_handle_doc},
{"close", (PyCFunction)do_multi_close, METH_NOARGS, multi_close_doc},
{"fdset", (PyCFunction)do_multi_fdset, METH_NOARGS, multi_fdset_doc},
{"info_read", (PyCFunction)do_multi_info_read, METH_VARARGS, multi_info_read_doc},
{"perform", (PyCFunction)do_multi_perform, METH_NOARGS, multi_perform_doc},
{"socket_action", (PyCFunction)do_multi_socket_action, METH_VARARGS, multi_socket_action_doc},
{"socket_all", (PyCFunction)do_multi_socket_all, METH_NOARGS, multi_socket_all_doc},
{"setopt", (PyCFunction)do_multi_setopt, METH_VARARGS, multi_setopt_doc},
{"timeout", (PyCFunction)do_multi_timeout, METH_NOARGS, multi_timeout_doc},
{"assign", (PyCFunction)do_multi_assign, METH_VARARGS, multi_assign_doc},
{"remove_handle", (PyCFunction)do_multi_remove_handle, METH_VARARGS, multi_remove_handle_doc},
{"select", (PyCFunction)do_multi_select, METH_VARARGS, multi_select_doc},
{"__getstate__", (PyCFunction)do_curlmulti_getstate, METH_NOARGS, NULL},
{"__setstate__", (PyCFunction)do_curlmulti_setstate, METH_VARARGS, NULL},
{NULL, NULL, 0, NULL}
};
/* --------------- setattr/getattr --------------- */
#if PY_MAJOR_VERSION >= 3
PYCURL_INTERNAL PyObject *
do_multi_getattro(PyObject *o, PyObject *n)
{
PyObject *v;
assert_multi_state((CurlMultiObject *)o);
v = PyObject_GenericGetAttr(o, n);
if( !v && PyErr_ExceptionMatches(PyExc_AttributeError) )
{
PyErr_Clear();
v = my_getattro(o, n, ((CurlMultiObject *)o)->dict,
curlmultiobject_constants, curlmultiobject_methods);
}
return v;
}
PYCURL_INTERNAL int
do_multi_setattro(PyObject *o, PyObject *n, PyObject *v)
{
assert_multi_state((CurlMultiObject *)o);
return my_setattro(&((CurlMultiObject *)o)->dict, n, v);
}
#else /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyObject *
do_multi_getattr(CurlMultiObject *co, char *name)
{
assert_multi_state(co);
return my_getattr((PyObject *)co, name, co->dict,
curlmultiobject_constants, curlmultiobject_methods);
}
PYCURL_INTERNAL int
do_multi_setattr(CurlMultiObject *co, char *name, PyObject *v)
{
assert_multi_state(co);
return my_setattr(&co->dict, name, v);
}
#endif /* PY_MAJOR_VERSION >= 3 */
PYCURL_INTERNAL PyTypeObject CurlMulti_Type = {
#if PY_MAJOR_VERSION >= 3
PyVarObject_HEAD_INIT(NULL, 0)
#else
PyObject_HEAD_INIT(NULL)
0, /* ob_size */
#endif
"pycurl.CurlMulti", /* tp_name */
sizeof(CurlMultiObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)do_multi_dealloc, /* tp_dealloc */
0, /* tp_print */
#if PY_MAJOR_VERSION >= 3
0, /* tp_getattr */
0, /* tp_setattr */
#else
(getattrfunc)do_multi_getattr, /* tp_getattr */
(setattrfunc)do_multi_setattr, /* tp_setattr */
#endif
0, /* tp_reserved */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
#if PY_MAJOR_VERSION >= 3
(getattrofunc)do_multi_getattro, /* tp_getattro */
(setattrofunc)do_multi_setattro, /* tp_setattro */
#else
0, /* tp_getattro */
0, /* tp_setattro */
#endif
0, /* tp_as_buffer */
PYCURL_TYPE_FLAGS, /* tp_flags */
multi_doc, /* tp_doc */
(traverseproc)do_multi_traverse, /* tp_traverse */
(inquiry)do_multi_clear, /* tp_clear */
0, /* tp_richcompare */
offsetof(CurlMultiObject, weakreflist), /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
curlmultiobject_methods, /* 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 */
PyType_GenericAlloc, /* tp_alloc */
(newfunc)do_multi_new, /* tp_new */
PyObject_GC_Del, /* tp_free */
};
/* vi:ts=4:et:nowrap
*/
pycurl-7.43.0.2/src/docstrings.c 0000644 0001750 0001750 00000072763 13304422053 015434 0 ustar me me 0000000 0000000 /* Generated file - do not edit. */
/* See doc/docstrings/ *.rst. */
#include "pycurl.h"
PYCURL_INTERNAL const char curl_doc[] = "Curl() -> New Curl object\n\
\n\
Creates a new :ref:`curlobject` which corresponds to a\n\
``CURL`` handle in libcurl. Curl objects automatically set\n\
CURLOPT_VERBOSE to 0, CURLOPT_NOPROGRESS to 1, provide a default\n\
CURLOPT_USERAGENT and setup CURLOPT_ERRORBUFFER to point to a\n\
private error buffer.\n\
\n\
Implicitly calls :py:func:`pycurl.global_init` if the latter has not yet been called.";
PYCURL_INTERNAL const char curl_close_doc[] = "close() -> None\n\
\n\
Close handle and end curl session.\n\
\n\
Corresponds to `curl_easy_cleanup`_ in libcurl. This method is\n\
automatically called by pycurl when a Curl object no longer has any\n\
references to it, but can also be called explicitly.\n\
\n\
.. _curl_easy_cleanup:\n\
https://curl.haxx.se/libcurl/c/curl_easy_cleanup.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\
\n\
Return value is a ``str`` instance on all Python versions.\n\
On Python 3, error buffer data is decoded using Python's default encoding\n\
at the time of the call. If this decoding fails, ``UnicodeDecodeError`` is\n\
raised. Use :ref:`errstr_raw ` to retrieve the error buffer\n\
as a byte string in this case.\n\
\n\
On Python 2, ``errstr`` and ``errstr_raw`` behave identically.";
PYCURL_INTERNAL const char curl_errstr_raw_doc[] = "errstr_raw() -> byte string\n\
\n\
Return the internal libcurl error buffer of this handle as a byte string.\n\
\n\
Return value is a ``str`` instance on Python 2 and ``bytes`` instance\n\
on Python 3. Unlike :ref:`errstr_raw `, ``errstr_raw``\n\
allows reading libcurl error buffer in Python 3 when its contents is not\n\
valid in Python's default encoding.\n\
\n\
On Python 2, ``errstr`` and ``errstr_raw`` behave identically.\n\
\n\
*Added in version 7.43.0.2.*";
PYCURL_INTERNAL const char curl_getinfo_doc[] = "getinfo(option) -> Result\n\
\n\
Extract and return information from a curl session,\n\
decoding string data in Python's default encoding at the time of the call.\n\
Corresponds to `curl_easy_getinfo`_ in libcurl.\n\
The ``getinfo`` method should not be called unless\n\
``perform`` has been called and finished.\n\
\n\
*option* is a constant corresponding to one of the\n\
``CURLINFO_*`` constants in libcurl. Most option constant names match\n\
the respective ``CURLINFO_*`` constant names with the ``CURLINFO_`` prefix\n\
removed, for example ``CURLINFO_CONTENT_TYPE`` is accessible as\n\
``pycurl.CONTENT_TYPE``. Exceptions to this rule are as follows:\n\
\n\
- ``CURLINFO_FILETIME`` is mapped as ``pycurl.INFO_FILETIME``\n\
- ``CURLINFO_COOKIELIST`` is mapped as ``pycurl.INFO_COOKIELIST``\n\
- ``CURLINFO_CERTINFO`` is mapped as ``pycurl.INFO_CERTINFO``\n\
- ``CURLINFO_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.INFO_RTSP_CLIENT_CSEQ``\n\
- ``CURLINFO_RTSP_CSEQ_RECV`` is mapped as ``pycurl.INFO_RTSP_CSEQ_RECV``\n\
- ``CURLINFO_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.INFO_RTSP_SERVER_CSEQ``\n\
- ``CURLINFO_RTSP_SESSION_ID`` is mapped as ``pycurl.INFO_RTSP_SESSION_ID``\n\
\n\
The type of return value depends on the option, as follows:\n\
\n\
- Options documented by libcurl to return an integer value return a\n\
Python integer (``long`` on Python 2, ``int`` on Python 3).\n\
- Options documented by libcurl to return a floating point value\n\
return a Python ``float``.\n\
- Options documented by libcurl to return a string value\n\
return a Python string (``str`` on Python 2 and Python 3).\n\
On Python 2, the string contains whatever data libcurl returned.\n\
On Python 3, the data returned by libcurl is decoded using the\n\
default string encoding at the time of the call.\n\
If the data cannot be decoded using the default encoding, ``UnicodeDecodeError``\n\
is raised. Use :ref:`getinfo_raw `\n\
to retrieve the data as ``bytes`` in these\n\
cases.\n\
- ``SSL_ENGINES`` and ``INFO_COOKIELIST`` return a list of strings.\n\
The same encoding caveats apply; use :ref:`getinfo_raw `\n\
to retrieve the\n\
data as a list of byte strings.\n\
- ``INFO_CERTINFO`` returns a list with one element\n\
per certificate in the chain, starting with the leaf; each element is a\n\
sequence of *(key, value)* tuples where both ``key`` and ``value`` are\n\
strings. String encoding caveats apply; use :ref:`getinfo_raw `\n\
to retrieve\n\
certificate data as byte strings.\n\
\n\
On Python 2, ``getinfo`` and ``getinfo_raw`` behave identically.\n\
\n\
Example usage::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt(pycurl.OPT_CERTINFO, 1)\n\
c.setopt(pycurl.URL, \"https://python.org\")\n\
c.setopt(pycurl.FOLLOWLOCATION, 1)\n\
c.perform()\n\
print(c.getinfo(pycurl.HTTP_CODE))\n\
# --> 200\n\
print(c.getinfo(pycurl.EFFECTIVE_URL))\n\
# --> \"https://www.python.org/\"\n\
certinfo = c.getinfo(pycurl.INFO_CERTINFO)\n\
print(certinfo)\n\
# --> [(('Subject', 'C = AU, ST = Some-State, O = PycURL test suite,\n\
CN = localhost'), ('Issuer', 'C = AU, ST = Some-State,\n\
O = PycURL test suite, OU = localhost, CN = localhost'),\n\
('Version', '0'), ...)]\n\
\n\
\n\
Raises pycurl.error exception upon failure.\n\
\n\
.. _curl_easy_getinfo:\n\
https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html";
PYCURL_INTERNAL const char curl_getinfo_raw_doc[] = "getinfo_raw(option) -> Result\n\
\n\
Extract and return information from a curl session,\n\
returning string data as byte strings.\n\
Corresponds to `curl_easy_getinfo`_ in libcurl.\n\
The ``getinfo_raw`` method should not be called unless\n\
``perform`` has been called and finished.\n\
\n\
*option* is a constant corresponding to one of the\n\
``CURLINFO_*`` constants in libcurl. Most option constant names match\n\
the respective ``CURLINFO_*`` constant names with the ``CURLINFO_`` prefix\n\
removed, for example ``CURLINFO_CONTENT_TYPE`` is accessible as\n\
``pycurl.CONTENT_TYPE``. Exceptions to this rule are as follows:\n\
\n\
- ``CURLINFO_FILETIME`` is mapped as ``pycurl.INFO_FILETIME``\n\
- ``CURLINFO_COOKIELIST`` is mapped as ``pycurl.INFO_COOKIELIST``\n\
- ``CURLINFO_CERTINFO`` is mapped as ``pycurl.INFO_CERTINFO``\n\
- ``CURLINFO_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.INFO_RTSP_CLIENT_CSEQ``\n\
- ``CURLINFO_RTSP_CSEQ_RECV`` is mapped as ``pycurl.INFO_RTSP_CSEQ_RECV``\n\
- ``CURLINFO_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.INFO_RTSP_SERVER_CSEQ``\n\
- ``CURLINFO_RTSP_SESSION_ID`` is mapped as ``pycurl.INFO_RTSP_SESSION_ID``\n\
\n\
The type of return value depends on the option, as follows:\n\
\n\
- Options documented by libcurl to return an integer value return a\n\
Python integer (``long`` on Python 2, ``int`` on Python 3).\n\
- Options documented by libcurl to return a floating point value\n\
return a Python ``float``.\n\
- Options documented by libcurl to return a string value\n\
return a Python byte string (``str`` on Python 2, ``bytes`` on Python 3).\n\
The string contains whatever data libcurl returned.\n\
Use :ref:`getinfo ` to retrieve this data as a Unicode string on Python 3.\n\
- ``SSL_ENGINES`` and ``INFO_COOKIELIST`` return a list of byte strings.\n\
The same encoding caveats apply; use :ref:`getinfo ` to retrieve the\n\
data as a list of potentially Unicode strings.\n\
- ``INFO_CERTINFO`` returns a list with one element\n\
per certificate in the chain, starting with the leaf; each element is a\n\
sequence of *(key, value)* tuples where both ``key`` and ``value`` are\n\
byte strings. String encoding caveats apply; use :ref:`getinfo `\n\
to retrieve\n\
certificate data as potentially Unicode strings.\n\
\n\
On Python 2, ``getinfo`` and ``getinfo_raw`` behave identically.\n\
\n\
Example usage::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt(pycurl.OPT_CERTINFO, 1)\n\
c.setopt(pycurl.URL, \"https://python.org\")\n\
c.setopt(pycurl.FOLLOWLOCATION, 1)\n\
c.perform()\n\
print(c.getinfo_raw(pycurl.HTTP_CODE))\n\
# --> 200\n\
print(c.getinfo_raw(pycurl.EFFECTIVE_URL))\n\
# --> b\"https://www.python.org/\"\n\
certinfo = c.getinfo_raw(pycurl.INFO_CERTINFO)\n\
print(certinfo)\n\
# --> [((b'Subject', b'C = AU, ST = Some-State, O = PycURL test suite,\n\
CN = localhost'), (b'Issuer', b'C = AU, ST = Some-State,\n\
O = PycURL test suite, OU = localhost, CN = localhost'),\n\
(b'Version', b'0'), ...)]\n\
\n\
\n\
Raises pycurl.error exception upon failure.\n\
\n\
*Added in version 7.43.0.2.*\n\
\n\
.. _curl_easy_getinfo:\n\
https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html";
PYCURL_INTERNAL const char curl_pause_doc[] = "pause(bitmask) -> None\n\
\n\
Pause or unpause a curl handle. Bitmask should be a value such as\n\
PAUSE_RECV or PAUSE_CONT.\n\
\n\
Corresponds to `curl_easy_pause`_ in libcurl. The argument should be\n\
derived from the ``PAUSE_RECV``, ``PAUSE_SEND``, ``PAUSE_ALL`` and\n\
``PAUSE_CONT`` constants.\n\
\n\
Raises pycurl.error exception upon failure.\n\
\n\
.. _curl_easy_pause: https://curl.haxx.se/libcurl/c/curl_easy_pause.html";
PYCURL_INTERNAL const char curl_perform_doc[] = "perform() -> None\n\
\n\
Perform a file transfer.\n\
\n\
Corresponds to `curl_easy_perform`_ in libcurl.\n\
\n\
Raises pycurl.error exception upon failure.\n\
\n\
.. _curl_easy_perform:\n\
https://curl.haxx.se/libcurl/c/curl_easy_perform.html";
PYCURL_INTERNAL const char curl_perform_rb_doc[] = "perform_rb() -> response_body\n\
\n\
Perform a file transfer and return response body as a byte string.\n\
\n\
This method arranges for response body to be saved in a StringIO\n\
(Python 2) or BytesIO (Python 3) instance, then invokes :ref:`perform `\n\
to perform the file transfer, then returns the value of the StringIO/BytesIO\n\
instance which is a ``str`` instance on Python 2 and ``bytes`` instance\n\
on Python 3. Errors during transfer raise ``pycurl.error`` exceptions\n\
just like in :ref:`perform `.\n\
\n\
Use :ref:`perform_rs ` to retrieve response body as a string\n\
(``str`` instance on both Python 2 and 3).\n\
\n\
Raises ``pycurl.error`` exception upon failure.\n\
\n\
*Added in version 7.43.0.2.*";
PYCURL_INTERNAL const char curl_perform_rs_doc[] = "perform_rs() -> response_body\n\
\n\
Perform a file transfer and return response body as a string.\n\
\n\
On Python 2, this method arranges for response body to be saved in a StringIO\n\
instance, then invokes :ref:`perform `\n\
to perform the file transfer, then returns the value of the StringIO instance.\n\
This behavior is identical to :ref:`perform_rb `.\n\
\n\
On Python 3, this method arranges for response body to be saved in a BytesIO\n\
instance, then invokes :ref:`perform `\n\
to perform the file transfer, then decodes the response body in Python's\n\
default encoding and returns the decoded body as a Unicode string\n\
(``str`` instance). *Note:* decoding happens after the transfer finishes,\n\
thus an encoding error implies the transfer/network operation succeeded.\n\
\n\
Any transfer errors raise ``pycurl.error`` exception,\n\
just like in :ref:`perform `.\n\
\n\
Use :ref:`perform_rb ` to retrieve response body as a byte\n\
string (``bytes`` instance on Python 3) without attempting to decode it.\n\
\n\
Raises ``pycurl.error`` exception upon failure.\n\
\n\
*Added in version 7.43.0.2.*";
PYCURL_INTERNAL const char curl_reset_doc[] = "reset() -> None\n\
\n\
Reset all options set on curl handle to default values, but preserves\n\
live connections, session ID cache, DNS cache, cookies, and shares.\n\
\n\
Corresponds to `curl_easy_reset`_ in libcurl.\n\
\n\
.. _curl_easy_reset: https://curl.haxx.se/libcurl/c/curl_easy_reset.html";
PYCURL_INTERNAL const char curl_set_ca_certs_doc[] = "set_ca_certs() -> None\n\
\n\
Load ca certs from provided unicode string.\n\
\n\
Note that certificates will be added only when cURL starts new connection.";
PYCURL_INTERNAL const char curl_setopt_doc[] = "setopt(option, value) -> None\n\
\n\
Set curl session option. Corresponds to `curl_easy_setopt`_ in libcurl.\n\
\n\
*option* specifies which option to set. PycURL defines constants\n\
corresponding to ``CURLOPT_*`` constants in libcurl, except that\n\
the ``CURLOPT_`` prefix is removed. For example, ``CURLOPT_URL`` is\n\
exposed in PycURL as ``pycurl.URL``, with some exceptions as detailed below.\n\
For convenience, ``CURLOPT_*``\n\
constants are also exposed on the Curl objects themselves::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt(pycurl.URL, \"http://www.python.org/\")\n\
# Same as:\n\
c.setopt(c.URL, \"http://www.python.org/\")\n\
\n\
The following are exceptions to option constant naming convention:\n\
\n\
- ``CURLOPT_FILETIME`` is mapped as ``pycurl.OPT_FILETIME``\n\
- ``CURLOPT_CERTINFO`` is mapped as ``pycurl.OPT_CERTINFO``\n\
- ``CURLOPT_COOKIELIST`` is mapped as ``pycurl.COOKIELIST``\n\
and, as of PycURL 7.43.0.2, also as ``pycurl.OPT_COOKIELIST``\n\
- ``CURLOPT_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.OPT_RTSP_CLIENT_CSEQ``\n\
- ``CURLOPT_RTSP_REQUEST`` is mapped as ``pycurl.OPT_RTSP_REQUEST``\n\
- ``CURLOPT_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.OPT_RTSP_SERVER_CSEQ``\n\
- ``CURLOPT_RTSP_SESSION_ID`` is mapped as ``pycurl.OPT_RTSP_SESSION_ID``\n\
- ``CURLOPT_RTSP_STREAM_URI`` is mapped as ``pycurl.OPT_RTSP_STREAM_URI``\n\
- ``CURLOPT_RTSP_TRANSPORT`` is mapped as ``pycurl.OPT_RTSP_TRANSPORT``\n\
\n\
*value* specifies the value to set the option to. Different options accept\n\
values of different types:\n\
\n\
- Options specified by `curl_easy_setopt`_ as accepting ``1`` or an\n\
integer value accept Python integers, long integers (on Python 2.x) and\n\
booleans::\n\
\n\
c.setopt(pycurl.FOLLOWLOCATION, True)\n\
c.setopt(pycurl.FOLLOWLOCATION, 1)\n\
# Python 2.x only:\n\
c.setopt(pycurl.FOLLOWLOCATION, 1L)\n\
\n\
- Options specified as accepting strings by ``curl_easy_setopt`` accept\n\
byte strings (``str`` on Python 2, ``bytes`` on Python 3) and\n\
Unicode strings with ASCII code points only.\n\
For more information, please refer to :ref:`unicode`. Example::\n\
\n\
c.setopt(pycurl.URL, \"http://www.python.org/\")\n\
c.setopt(pycurl.URL, u\"http://www.python.org/\")\n\
# Python 3.x only:\n\
c.setopt(pycurl.URL, b\"http://www.python.org/\")\n\
\n\
- ``HTTP200ALIASES``, ``HTTPHEADER``, ``POSTQUOTE``, ``PREQUOTE``,\n\
``PROXYHEADER`` and\n\
``QUOTE`` accept a list or tuple of strings. The same rules apply to these\n\
strings as do to string option values. Example::\n\
\n\
c.setopt(pycurl.HTTPHEADER, [\"Accept:\"])\n\
c.setopt(pycurl.HTTPHEADER, (\"Accept:\",))\n\
\n\
- ``READDATA`` accepts a file object or any Python object which has\n\
a ``read`` method. On Python 2, a file object will be passed directly\n\
to libcurl and may result in greater transfer efficiency, unless\n\
PycURL has been compiled with ``AVOID_STDIO`` option.\n\
On Python 3 and on Python 2 when the value is not a true file object,\n\
``READDATA`` is emulated in PycURL via ``READFUNCTION``.\n\
The file should generally be opened in binary mode. Example::\n\
\n\
f = open('file.txt', 'rb')\n\
c.setopt(c.READDATA, f)\n\
\n\
- ``WRITEDATA`` and ``WRITEHEADER`` accept a file object or any Python\n\
object which has a ``write`` method. On Python 2, a file object will\n\
be passed directly to libcurl and may result in greater transfer efficiency,\n\
unless PycURL has been compiled with ``AVOID_STDIO`` option.\n\
On Python 3 and on Python 2 when the value is not a true file object,\n\
``WRITEDATA`` is emulated in PycURL via ``WRITEFUNCTION``.\n\
The file should generally be opened in binary mode. Example::\n\
\n\
f = open('/dev/null', 'wb')\n\
c.setopt(c.WRITEDATA, f)\n\
\n\
- ``*FUNCTION`` options accept a function. Supported callbacks are documented\n\
in :ref:`callbacks`. Example::\n\
\n\
# Python 2\n\
import StringIO\n\
b = StringIO.StringIO()\n\
c.setopt(pycurl.WRITEFUNCTION, b.write)\n\
\n\
- ``SHARE`` option accepts a :ref:`curlshareobject`.\n\
\n\
It is possible to set integer options - and only them - that PycURL does\n\
not know about by using the numeric value of the option constant directly.\n\
For example, ``pycurl.VERBOSE`` has the value 42, and may be set as follows::\n\
\n\
c.setopt(42, 1)\n\
\n\
*setopt* can reset some options to their default value, performing the job of\n\
:py:meth:`pycurl.Curl.unsetopt`, if ``None`` is passed\n\
for the option value. The following two calls are equivalent::\n\
\n\
c.setopt(c.URL, None)\n\
c.unsetopt(c.URL)\n\
\n\
Raises TypeError when the option value is not of a type accepted by the\n\
respective option, and pycurl.error exception when libcurl rejects the\n\
option or its value.\n\
\n\
.. _curl_easy_setopt: https://curl.haxx.se/libcurl/c/curl_easy_setopt.html";
PYCURL_INTERNAL const char curl_setopt_string_doc[] = "setopt_string(option, value) -> None\n\
\n\
Set curl session option to a string value.\n\
\n\
This method allows setting string options that are not officially supported\n\
by PycURL, for example because they did not exist when the version of PycURL\n\
being used was released.\n\
:py:meth:`pycurl.Curl.setopt` should be used for setting options that\n\
PycURL knows about.\n\
\n\
**Warning:** No checking is performed that *option* does, in fact,\n\
expect a string value. Using this method incorrectly can crash the program\n\
and may lead to a security vulnerability.\n\
Furthermore, it is on the application to ensure that the *value* object\n\
does not get garbage collected while libcurl is using it.\n\
libcurl copies most string options but not all; one option whose value\n\
is not copied by libcurl is `CURLOPT_POSTFIELDS`_.\n\
\n\
*option* would generally need to be given as an integer literal rather than\n\
a symbolic constant.\n\
\n\
*value* can be a binary string or a Unicode string using ASCII code points,\n\
same as with string options given to PycURL elsewhere.\n\
\n\
Example setting URL via ``setopt_string``::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt_string(10002, \"http://www.python.org/\")\n\
\n\
.. _CURLOPT_POSTFIELDS: https://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html";
PYCURL_INTERNAL const char curl_unsetopt_doc[] = "unsetopt(option) -> None\n\
\n\
Reset curl session option to its default value.\n\
\n\
Only some curl options may be reset via this method.\n\
\n\
libcurl does not provide a general way to reset a single option to its default value;\n\
:py:meth:`pycurl.Curl.reset` resets all options to their default values,\n\
otherwise :py:meth:`pycurl.Curl.setopt` must be called with whatever value\n\
is the default. For convenience, PycURL provides this unsetopt method\n\
to reset some of the options to their default values.\n\
\n\
Raises pycurl.error exception on failure.\n\
\n\
``c.unsetopt(option)`` is equivalent to ``c.setopt(option, None)``.";
PYCURL_INTERNAL const char multi_doc[] = "CurlMulti() -> New CurlMulti object\n\
\n\
Creates a new :ref:`curlmultiobject` which corresponds to\n\
a ``CURLM`` handle in libcurl.";
PYCURL_INTERNAL const char multi_add_handle_doc[] = "add_handle(Curl object) -> None\n\
\n\
Corresponds to `curl_multi_add_handle`_ in libcurl. This method adds an\n\
existing and valid Curl object to the CurlMulti object.\n\
\n\
*Changed in version 7.43.0.2:* add_handle now ensures that the Curl object\n\
is not garbage collected while it is being used by a CurlMulti object.\n\
Previously application had to maintain an outstanding reference to the Curl\n\
object to keep it from being garbage collected.\n\
\n\
.. _curl_multi_add_handle:\n\
https://curl.haxx.se/libcurl/c/curl_multi_add_handle.html";
PYCURL_INTERNAL const char multi_assign_doc[] = "assign(sockfd, object) -> None\n\
\n\
Creates an association in the multi handle between the given socket and\n\
a private object in the application.\n\
Corresponds to `curl_multi_assign`_ in libcurl.\n\
\n\
.. _curl_multi_assign: https://curl.haxx.se/libcurl/c/curl_multi_assign.html";
PYCURL_INTERNAL const char multi_close_doc[] = "close() -> None\n\
\n\
Corresponds to `curl_multi_cleanup`_ in libcurl. This method is\n\
automatically called by pycurl when a CurlMulti object no longer has any\n\
references to it, but can also be called explicitly.\n\
\n\
.. _curl_multi_cleanup:\n\
https://curl.haxx.se/libcurl/c/curl_multi_cleanup.html";
PYCURL_INTERNAL const char multi_fdset_doc[] = "fdset() -> tuple of lists with active file descriptors, readable, writeable, exceptions\n\
\n\
Returns a tuple of three lists that can be passed to the select.select() method.\n\
\n\
Corresponds to `curl_multi_fdset`_ in libcurl. This method extracts the\n\
file descriptor information from a CurlMulti object. The returned lists can\n\
be used with the ``select`` module to poll for events.\n\
\n\
Example usage::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt(pycurl.URL, \"https://curl.haxx.se\")\n\
m = pycurl.CurlMulti()\n\
m.add_handle(c)\n\
while 1:\n\
ret, num_handles = m.perform()\n\
if ret != pycurl.E_CALL_MULTI_PERFORM: break\n\
while num_handles:\n\
apply(select.select, m.fdset() + (1,))\n\
while 1:\n\
ret, num_handles = m.perform()\n\
if ret != pycurl.E_CALL_MULTI_PERFORM: break\n\
\n\
.. _curl_multi_fdset:\n\
https://curl.haxx.se/libcurl/c/curl_multi_fdset.html";
PYCURL_INTERNAL const char multi_info_read_doc[] = "info_read([max_objects]) -> tuple(number of queued messages, a list of successful objects, a list of failed objects)\n\
\n\
Returns a tuple (number of queued handles, [curl objects]).\n\
\n\
Corresponds to the `curl_multi_info_read`_ function in libcurl. This\n\
method extracts at most *max* messages from the multi stack and returns them\n\
in two lists. The first list contains the handles which completed\n\
successfully and the second list contains a tuple *(curl object, curl error\n\
number, curl error message)* for each failed curl object. The number of\n\
queued messages after this method has been called is also returned.\n\
\n\
.. _curl_multi_info_read:\n\
https://curl.haxx.se/libcurl/c/curl_multi_info_read.html";
PYCURL_INTERNAL const char multi_perform_doc[] = "perform() -> tuple of status and the number of active Curl objects\n\
\n\
Corresponds to `curl_multi_perform`_ in libcurl.\n\
\n\
.. _curl_multi_perform:\n\
https://curl.haxx.se/libcurl/c/curl_multi_perform.html";
PYCURL_INTERNAL const char multi_remove_handle_doc[] = "remove_handle(Curl object) -> None\n\
\n\
Corresponds to `curl_multi_remove_handle`_ in libcurl. This method\n\
removes an existing and valid Curl object from the CurlMulti object.\n\
\n\
IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference\n\
from the Curl object (and thus does not decrease the reference count on the\n\
Curl object).\n\
\n\
.. _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\
\n\
Returns result from doing a select() on the curl multi file descriptor\n\
with the given timeout.\n\
\n\
This is a convenience function which simplifies the combined use of\n\
``fdset()`` and the ``select`` module.\n\
\n\
Example usage::\n\
\n\
import pycurl\n\
c = pycurl.Curl()\n\
c.setopt(pycurl.URL, \"https://curl.haxx.se\")\n\
m = pycurl.CurlMulti()\n\
m.add_handle(c)\n\
while 1:\n\
ret, num_handles = m.perform()\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\
while 1:\n\
ret, num_handles = m.perform()\n\
if ret != pycurl.E_CALL_MULTI_PERFORM: break";
PYCURL_INTERNAL const char multi_setopt_doc[] = "setopt(option, value) -> None\n\
\n\
Set curl multi option. Corresponds to `curl_multi_setopt`_ in libcurl.\n\
\n\
*option* specifies which option to set. PycURL defines constants\n\
corresponding to ``CURLMOPT_*`` constants in libcurl, except that\n\
the ``CURLMOPT_`` prefix is replaced with ``M_`` prefix.\n\
For example, ``CURLMOPT_PIPELINING`` is\n\
exposed in PycURL as ``pycurl.M_PIPELINING``. For convenience, ``CURLMOPT_*``\n\
constants are also exposed on CurlMulti objects::\n\
\n\
import pycurl\n\
m = pycurl.CurlMulti()\n\
m.setopt(pycurl.M_PIPELINING, 1)\n\
# Same as:\n\
m.setopt(m.M_PIPELINING, 1)\n\
\n\
*value* specifies the value to set the option to. Different options accept\n\
values of different types:\n\
\n\
- Options specified by `curl_multi_setopt`_ as accepting ``1`` or an\n\
integer value accept Python integers, long integers (on Python 2.x) and\n\
booleans::\n\
\n\
m.setopt(pycurl.M_PIPELINING, True)\n\
m.setopt(pycurl.M_PIPELINING, 1)\n\
# Python 2.x only:\n\
m.setopt(pycurl.M_PIPELINING, 1L)\n\
\n\
- ``*FUNCTION`` options accept a function. Supported callbacks are\n\
``CURLMOPT_SOCKETFUNCTION`` AND ``CURLMOPT_TIMERFUNCTION``. Please refer to\n\
the PycURL test suite for examples on using the callbacks.\n\
\n\
Raises TypeError when the option value is not of a type accepted by the\n\
respective option, and pycurl.error exception when libcurl rejects the\n\
option or its value.\n\
\n\
.. _curl_multi_setopt: https://curl.haxx.se/libcurl/c/curl_multi_setopt.html";
PYCURL_INTERNAL const char multi_socket_action_doc[] = "socket_action(sockfd, ev_bitmask) -> tuple\n\
\n\
Returns result from doing a socket_action() on the curl multi file descriptor\n\
with the given timeout.\n\
Corresponds to `curl_multi_socket_action`_ in libcurl.\n\
\n\
.. _curl_multi_socket_action: https://curl.haxx.se/libcurl/c/curl_multi_socket_action.html";
PYCURL_INTERNAL const char multi_socket_all_doc[] = "socket_all() -> Tuple.\n\
\n\
Returns result from doing a socket_all() on the curl multi file descriptor\n\
with the given timeout.";
PYCURL_INTERNAL const char multi_timeout_doc[] = "timeout() -> int\n\
\n\
Returns how long to wait for action before proceeding.\n\
Corresponds to `curl_multi_timeout`_ in libcurl.\n\
\n\
.. _curl_multi_timeout: https://curl.haxx.se/libcurl/c/curl_multi_timeout.html";
PYCURL_INTERNAL const char pycurl_global_cleanup_doc[] = "global_cleanup() -> None\n\
\n\
Cleanup curl environment.\n\
\n\
Corresponds to `curl_global_cleanup`_ in libcurl.\n\
\n\
.. _curl_global_cleanup: https://curl.haxx.se/libcurl/c/curl_global_cleanup.html";
PYCURL_INTERNAL const char pycurl_global_init_doc[] = "global_init(option) -> None\n\
\n\
Initialize curl environment.\n\
\n\
*option* is one of the constants pycurl.GLOBAL_SSL, pycurl.GLOBAL_WIN32,\n\
pycurl.GLOBAL_ALL, pycurl.GLOBAL_NOTHING, pycurl.GLOBAL_DEFAULT.\n\
\n\
Corresponds to `curl_global_init`_ in libcurl.\n\
\n\
.. _curl_global_init: https://curl.haxx.se/libcurl/c/curl_global_init.html";
PYCURL_INTERNAL const char pycurl_module_doc[] = "This module implements an interface to the cURL library.\n\
\n\
Types:\n\
\n\
Curl() -> New object. Create a new curl object.\n\
CurlMulti() -> New object. Create a new curl multi object.\n\
CurlShare() -> New object. Create a new curl share object.\n\
\n\
Functions:\n\
\n\
global_init(option) -> None. Initialize curl environment.\n\
global_cleanup() -> None. Cleanup curl environment.\n\
version_info() -> tuple. Return version information.";
PYCURL_INTERNAL const char pycurl_version_info_doc[] = "version_info() -> tuple\n\
\n\
Returns a 12-tuple with the version info.\n\
\n\
Corresponds to `curl_version_info`_ in libcurl. Returns a tuple of\n\
information which is similar to the ``curl_version_info_data`` struct\n\
returned by ``curl_version_info()`` in libcurl.\n\
\n\
Example usage::\n\
\n\
>>> import pycurl\n\
>>> pycurl.version_info()\n\
(3, '7.33.0', 467200, 'amd64-portbld-freebsd9.1', 33436, 'OpenSSL/0.9.8x',\n\
0, '1.2.7', ('dict', 'file', 'ftp', 'ftps', 'gopher', 'http', 'https',\n\
'imap', 'imaps', 'pop3', 'pop3s', 'rtsp', 'smtp', 'smtps', 'telnet',\n\
'tftp'), None, 0, None)\n\
\n\
.. _curl_version_info: https://curl.haxx.se/libcurl/c/curl_version_info.html";
PYCURL_INTERNAL const char share_doc[] = "CurlShare() -> New CurlShare object\n\
\n\
Creates a new :ref:`curlshareobject` which corresponds to a\n\
``CURLSH`` handle in libcurl. CurlShare objects is what you pass as an\n\
argument to the SHARE option on :ref:`Curl objects `.";
PYCURL_INTERNAL const char share_close_doc[] = "close() -> None\n\
\n\
Close shared handle.\n\
\n\
Corresponds to `curl_share_cleanup`_ in libcurl. This method is\n\
automatically called by pycurl when a CurlShare object no longer has\n\
any references to it, but can also be called explicitly.\n\
\n\
.. _curl_share_cleanup:\n\
https://curl.haxx.se/libcurl/c/curl_share_cleanup.html";
PYCURL_INTERNAL const char share_setopt_doc[] = "setopt(option, value) -> None\n\
\n\
Set curl share option.\n\
\n\
Corresponds to `curl_share_setopt`_ in libcurl, where *option* is\n\
specified with the ``CURLSHOPT_*`` constants in libcurl, except that the\n\
``CURLSHOPT_`` prefix has been changed to ``SH_``. Currently, *value* must be\n\
either ``LOCK_DATA_COOKIE`` or ``LOCK_DATA_DNS``.\n\
\n\
Example usage::\n\
\n\
import pycurl\n\
curl = pycurl.Curl()\n\
s = pycurl.CurlShare()\n\
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)\n\
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)\n\
curl.setopt(pycurl.URL, 'https://curl.haxx.se')\n\
curl.setopt(pycurl.SHARE, s)\n\
curl.perform()\n\
curl.close()\n\
\n\
Raises pycurl.error exception upon failure.\n\
\n\
.. _curl_share_setopt:\n\
https://curl.haxx.se/libcurl/c/curl_share_setopt.html";
pycurl-7.43.0.2/python/ 0000755 0001750 0001750 00000000000 13304422066 013630 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/python/curl/ 0000755 0001750 0001750 00000000000 13304422066 014575 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/python/curl/__init__.py 0000644 0001750 0001750 00000016033 13211045165 016707 0 ustar me me 0000000 0000000 '''A high-level interface to the pycurl extension'''
# ** mfx NOTE: the CGI class uses "black magic" using COOKIEFILE in
# combination with a non-existant file name. See the libcurl docs
# for more info.
import sys, pycurl
py3 = sys.version_info[0] == 3
# python 2/3 compatibility
if py3:
import urllib.parse as urllib_parse
from urllib.parse import urljoin
from io import BytesIO
else:
import urllib as urllib_parse
from urlparse import urljoin
try:
from cStringIO import StringIO as BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
except ImportError:
pass
else:
signal.signal(SIGPIPE, SIG_IGN)
class Curl:
"High-level interface to pycurl functions."
def __init__(self, base_url="", fakeheaders=[]):
self.handle = pycurl.Curl()
# These members might be set.
self.set_url(base_url)
self.verbosity = 0
self.fakeheaders = fakeheaders
# Nothing past here should be modified by the caller.
self.payload = None
self.payload_io = BytesIO()
self.hrd = ""
# Verify that we've got the right site; harmless on a non-SSL connect.
self.set_option(pycurl.SSL_VERIFYHOST, 2)
# Follow redirects in case it wants to take us to a CGI...
self.set_option(pycurl.FOLLOWLOCATION, 1)
self.set_option(pycurl.MAXREDIRS, 5)
self.set_option(pycurl.NOSIGNAL, 1)
# Setting this option with even a nonexistent file makes libcurl
# handle cookie capture and playback automatically.
self.set_option(pycurl.COOKIEFILE, "/dev/null")
# Set timeouts to avoid hanging too long
self.set_timeout(30)
# Use password identification from .netrc automatically
self.set_option(pycurl.NETRC, 1)
self.set_option(pycurl.WRITEFUNCTION, self.payload_io.write)
def header_callback(x):
self.hdr += x.decode('ascii')
self.set_option(pycurl.HEADERFUNCTION, header_callback)
def set_timeout(self, timeout):
"Set timeout for a retrieving an object"
self.set_option(pycurl.TIMEOUT, timeout)
def set_url(self, url):
"Set the base URL to be retrieved."
self.base_url = url
self.set_option(pycurl.URL, self.base_url)
def set_option(self, *args):
"Set an option on the retrieval."
self.handle.setopt(*args)
def set_verbosity(self, level):
"Set verbosity to 1 to see transactions."
self.set_option(pycurl.VERBOSE, level)
def __request(self, relative_url=None):
"Perform the pending request."
if self.fakeheaders:
self.set_option(pycurl.HTTPHEADER, self.fakeheaders)
if relative_url:
self.set_option(pycurl.URL, urljoin(self.base_url, relative_url))
self.payload = None
self.payload_io.seek(0)
self.payload_io.truncate()
self.hdr = ""
self.handle.perform()
self.payload = self.payload_io.getvalue()
return self.payload
def get(self, url="", params=None):
"Ship a GET request for a specified URL, capture the response."
if params:
url += "?" + urllib_parse.urlencode(params)
self.set_option(pycurl.HTTPGET, 1)
return self.__request(url)
def post(self, cgi, params):
"Ship a POST request to a specified CGI, capture the response."
self.set_option(pycurl.POST, 1)
self.set_option(pycurl.POSTFIELDS, urllib_parse.urlencode(params))
return self.__request(cgi)
def body(self):
"Return the body from the last response."
return self.payload
def header(self):
"Return the header from the last response."
return self.hdr
def get_info(self, *args):
"Get information about retrieval."
return self.handle.getinfo(*args)
def info(self):
"Return a dictionary with all info on the last response."
m = {}
m['effective-url'] = self.handle.getinfo(pycurl.EFFECTIVE_URL)
m['http-code'] = self.handle.getinfo(pycurl.HTTP_CODE)
m['total-time'] = self.handle.getinfo(pycurl.TOTAL_TIME)
m['namelookup-time'] = self.handle.getinfo(pycurl.NAMELOOKUP_TIME)
m['connect-time'] = self.handle.getinfo(pycurl.CONNECT_TIME)
m['pretransfer-time'] = self.handle.getinfo(pycurl.PRETRANSFER_TIME)
m['redirect-time'] = self.handle.getinfo(pycurl.REDIRECT_TIME)
m['redirect-count'] = self.handle.getinfo(pycurl.REDIRECT_COUNT)
m['size-upload'] = self.handle.getinfo(pycurl.SIZE_UPLOAD)
m['size-download'] = self.handle.getinfo(pycurl.SIZE_DOWNLOAD)
m['speed-upload'] = self.handle.getinfo(pycurl.SPEED_UPLOAD)
m['header-size'] = self.handle.getinfo(pycurl.HEADER_SIZE)
m['request-size'] = self.handle.getinfo(pycurl.REQUEST_SIZE)
m['content-length-download'] = self.handle.getinfo(pycurl.CONTENT_LENGTH_DOWNLOAD)
m['content-length-upload'] = self.handle.getinfo(pycurl.CONTENT_LENGTH_UPLOAD)
m['content-type'] = self.handle.getinfo(pycurl.CONTENT_TYPE)
m['response-code'] = self.handle.getinfo(pycurl.RESPONSE_CODE)
m['speed-download'] = self.handle.getinfo(pycurl.SPEED_DOWNLOAD)
m['ssl-verifyresult'] = self.handle.getinfo(pycurl.SSL_VERIFYRESULT)
m['filetime'] = self.handle.getinfo(pycurl.INFO_FILETIME)
m['starttransfer-time'] = self.handle.getinfo(pycurl.STARTTRANSFER_TIME)
m['redirect-time'] = self.handle.getinfo(pycurl.REDIRECT_TIME)
m['redirect-count'] = self.handle.getinfo(pycurl.REDIRECT_COUNT)
m['http-connectcode'] = self.handle.getinfo(pycurl.HTTP_CONNECTCODE)
m['httpauth-avail'] = self.handle.getinfo(pycurl.HTTPAUTH_AVAIL)
m['proxyauth-avail'] = self.handle.getinfo(pycurl.PROXYAUTH_AVAIL)
m['os-errno'] = self.handle.getinfo(pycurl.OS_ERRNO)
m['num-connects'] = self.handle.getinfo(pycurl.NUM_CONNECTS)
m['ssl-engines'] = self.handle.getinfo(pycurl.SSL_ENGINES)
m['cookielist'] = self.handle.getinfo(pycurl.INFO_COOKIELIST)
m['lastsocket'] = self.handle.getinfo(pycurl.LASTSOCKET)
m['ftp-entry-path'] = self.handle.getinfo(pycurl.FTP_ENTRY_PATH)
return m
def answered(self, check):
"Did a given check string occur in the last payload?"
return self.payload.find(check) >= 0
def close(self):
"Close a session, freeing resources."
if self.handle:
self.handle.close()
self.handle = None
self.hdr = ""
self.payload = ""
def __del__(self):
self.close()
if __name__ == "__main__":
if len(sys.argv) < 2:
url = 'https://curl.haxx.se'
else:
url = sys.argv[1]
c = Curl()
c.get(url)
print(c.body())
print('='*74 + '\n')
import pprint
pprint.pprint(c.info())
print(c.get_info(pycurl.OS_ERRNO))
print(c.info()['os-errno'])
c.close()
pycurl-7.43.0.2/doc/ 0000755 0001750 0001750 00000000000 13304422066 013054 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/doc/unimplemented.rst 0000644 0001750 0001750 00000003623 13211045165 016456 0 ustar me me 0000000 0000000 Unimplemented Options And Constants
===================================
PycURL intentionally does not expose some of the libcurl options and constants.
This document explains libcurl symbols that were omitted from PycURL.
``*DATA`` options
-----------------
In libcurl, the ``*aDATA`` options set *client data* for various callbacks.
Each callback has a corresponding ``*DATA`` option.
In Python - a language with closures - such options are unnecessary.
For example, the following code invokes an instance's ``write`` method
which has full access to its class instance::
class Writer(object):
def __init__(self):
self.foo = True
def write(chunk):
# can use self.foo
writer = Writer()
curl = pycurl.Curl()
curl.setopt(curl.WRITEFUNCTION, writer.write)
As of version 7.19.3, PycURL does implement three ``*DATA`` options for
convenience:
``WRITEDATA``, ``HEADERDATA`` and ``READDATA``. These are equivalent to
setting the respective callback option with either a ``write`` or ``read``
method, as appropriate::
# equivalent pairs:
curl.setopt(curl.WRITEDATA, writer)
curl.setopt(curl.WRITEFUNCTION, writer.write)
curl.setopt(curl.HEADERDATA, writer)
curl.setopt(curl.HEADERFUNCTION, writer.write)
curl.setopt(curl.READDATA, reader)
curl.setopt(curl.READFUNCTION, reader.read)
``CURLINFO_TLS_SESSION``
------------------------
It is unclear how the SSL context should be exposed to Python code.
This option can be implemented if it finds a use case.
Undocumented symbols
--------------------
Some symbols are present in libcurl's `symbols in versions`_ document but
are not documented by libcurl. These symbols are not impemented by PycURL.
As of this writing, the following symbols are thusly omitted:
- ``CURLPAUSE_RECV_CONT``
- ``CURLPAUSE_SEND_CONT``
.. _symbols in versions: https://curl.haxx.se/libcurl/c/symbols-in-versions.html
pycurl-7.43.0.2/doc/docstrings/ 0000755 0001750 0001750 00000000000 13304422066 015233 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/doc/docstrings/pycurl_global_init.rst 0000644 0001750 0001750 00000000501 13211045165 021640 0 ustar me me 0000000 0000000 global_init(option) -> None
Initialize curl environment.
*option* is one of the constants pycurl.GLOBAL_SSL, pycurl.GLOBAL_WIN32,
pycurl.GLOBAL_ALL, pycurl.GLOBAL_NOTHING, pycurl.GLOBAL_DEFAULT.
Corresponds to `curl_global_init`_ in libcurl.
.. _curl_global_init: https://curl.haxx.se/libcurl/c/curl_global_init.html
pycurl-7.43.0.2/doc/docstrings/curl_unsetopt.rst 0000644 0001750 0001750 00000001127 13211045161 020666 0 ustar me me 0000000 0000000 unsetopt(option) -> None
Reset curl session option to its default value.
Only some curl options may be reset via this method.
libcurl does not provide a general way to reset a single option to its default value;
:py:meth:`pycurl.Curl.reset` resets all options to their default values,
otherwise :py:meth:`pycurl.Curl.setopt` must be called with whatever value
is the default. For convenience, PycURL provides this unsetopt method
to reset some of the options to their default values.
Raises pycurl.error exception on failure.
``c.unsetopt(option)`` is equivalent to ``c.setopt(option, None)``.
pycurl-7.43.0.2/doc/docstrings/multi_info_read.rst 0000644 0001750 0001750 00000001267 13211045165 021131 0 ustar me me 0000000 0000000 info_read([max_objects]) -> tuple(number of queued messages, a list of successful objects, a list of failed objects)
Returns a tuple (number of queued handles, [curl objects]).
Corresponds to the `curl_multi_info_read`_ function in libcurl. This
method extracts at most *max* messages from the multi stack and returns them
in two lists. The first list contains the handles which completed
successfully and the second list contains a tuple *(curl object, curl error
number, curl error message)* for each failed curl object. The number of
queued messages after this method has been called is also returned.
.. _curl_multi_info_read:
https://curl.haxx.se/libcurl/c/curl_multi_info_read.html
pycurl-7.43.0.2/doc/docstrings/curl.rst 0000644 0001750 0001750 00000000571 13211045142 016726 0 ustar me me 0000000 0000000 Curl() -> New Curl object
Creates a new :ref:`curlobject` which corresponds to a
``CURL`` handle in libcurl. Curl objects automatically set
CURLOPT_VERBOSE to 0, CURLOPT_NOPROGRESS to 1, provide a default
CURLOPT_USERAGENT and setup CURLOPT_ERRORBUFFER to point to a
private error buffer.
Implicitly calls :py:func:`pycurl.global_init` if the latter has not yet been called.
pycurl-7.43.0.2/doc/docstrings/pycurl_module.rst 0000644 0001750 0001750 00000000636 13211045142 020646 0 ustar me me 0000000 0000000 This module implements an interface to the cURL library.
Types:
Curl() -> New object. Create a new curl object.
CurlMulti() -> New object. Create a new curl multi object.
CurlShare() -> New object. Create a new curl share object.
Functions:
global_init(option) -> None. Initialize curl environment.
global_cleanup() -> None. Cleanup curl environment.
version_info() -> tuple. Return version information.
pycurl-7.43.0.2/doc/docstrings/share_setopt.rst 0000644 0001750 0001750 00000001375 13211045165 020471 0 ustar me me 0000000 0000000 setopt(option, value) -> None
Set curl share option.
Corresponds to `curl_share_setopt`_ in libcurl, where *option* is
specified with the ``CURLSHOPT_*`` constants in libcurl, except that the
``CURLSHOPT_`` prefix has been changed to ``SH_``. Currently, *value* must be
either ``LOCK_DATA_COOKIE`` or ``LOCK_DATA_DNS``.
Example usage::
import pycurl
curl = pycurl.Curl()
s = pycurl.CurlShare()
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_COOKIE)
s.setopt(pycurl.SH_SHARE, pycurl.LOCK_DATA_DNS)
curl.setopt(pycurl.URL, 'https://curl.haxx.se')
curl.setopt(pycurl.SHARE, s)
curl.perform()
curl.close()
Raises pycurl.error exception upon failure.
.. _curl_share_setopt:
https://curl.haxx.se/libcurl/c/curl_share_setopt.html
pycurl-7.43.0.2/doc/docstrings/curl_pause.rst 0000644 0001750 0001750 00000000616 13211045165 020130 0 ustar me me 0000000 0000000 pause(bitmask) -> None
Pause or unpause a curl handle. Bitmask should be a value such as
PAUSE_RECV or PAUSE_CONT.
Corresponds to `curl_easy_pause`_ in libcurl. The argument should be
derived from the ``PAUSE_RECV``, ``PAUSE_SEND``, ``PAUSE_ALL`` and
``PAUSE_CONT`` constants.
Raises pycurl.error exception upon failure.
.. _curl_easy_pause: https://curl.haxx.se/libcurl/c/curl_easy_pause.html
pycurl-7.43.0.2/doc/docstrings/curl_perform_rs.rst 0000644 0001750 0001750 00000002103 13301332107 021155 0 ustar me me 0000000 0000000 perform_rs() -> response_body
Perform a file transfer and return response body as a string.
On Python 2, this method arranges for response body to be saved in a StringIO
instance, then invokes :ref:`perform `
to perform the file transfer, then returns the value of the StringIO instance.
This behavior is identical to :ref:`perform_rb `.
On Python 3, this method arranges for response body to be saved in a BytesIO
instance, then invokes :ref:`perform `
to perform the file transfer, then decodes the response body in Python's
default encoding and returns the decoded body as a Unicode string
(``str`` instance). *Note:* decoding happens after the transfer finishes,
thus an encoding error implies the transfer/network operation succeeded.
Any transfer errors raise ``pycurl.error`` exception,
just like in :ref:`perform `.
Use :ref:`perform_rb ` to retrieve response body as a byte
string (``bytes`` instance on Python 3) without attempting to decode it.
Raises ``pycurl.error`` exception upon failure.
*Added in version 7.43.0.2.*
pycurl-7.43.0.2/doc/docstrings/curl_getinfo.rst 0000644 0001750 0001750 00000006261 13301167757 020464 0 ustar me me 0000000 0000000 getinfo(option) -> Result
Extract and return information from a curl session,
decoding string data in Python's default encoding at the time of the call.
Corresponds to `curl_easy_getinfo`_ in libcurl.
The ``getinfo`` method should not be called unless
``perform`` has been called and finished.
*option* is a constant corresponding to one of the
``CURLINFO_*`` constants in libcurl. Most option constant names match
the respective ``CURLINFO_*`` constant names with the ``CURLINFO_`` prefix
removed, for example ``CURLINFO_CONTENT_TYPE`` is accessible as
``pycurl.CONTENT_TYPE``. Exceptions to this rule are as follows:
- ``CURLINFO_FILETIME`` is mapped as ``pycurl.INFO_FILETIME``
- ``CURLINFO_COOKIELIST`` is mapped as ``pycurl.INFO_COOKIELIST``
- ``CURLINFO_CERTINFO`` is mapped as ``pycurl.INFO_CERTINFO``
- ``CURLINFO_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.INFO_RTSP_CLIENT_CSEQ``
- ``CURLINFO_RTSP_CSEQ_RECV`` is mapped as ``pycurl.INFO_RTSP_CSEQ_RECV``
- ``CURLINFO_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.INFO_RTSP_SERVER_CSEQ``
- ``CURLINFO_RTSP_SESSION_ID`` is mapped as ``pycurl.INFO_RTSP_SESSION_ID``
The type of return value depends on the option, as follows:
- Options documented by libcurl to return an integer value return a
Python integer (``long`` on Python 2, ``int`` on Python 3).
- Options documented by libcurl to return a floating point value
return a Python ``float``.
- Options documented by libcurl to return a string value
return a Python string (``str`` on Python 2 and Python 3).
On Python 2, the string contains whatever data libcurl returned.
On Python 3, the data returned by libcurl is decoded using the
default string encoding at the time of the call.
If the data cannot be decoded using the default encoding, ``UnicodeDecodeError``
is raised. Use :ref:`getinfo_raw `
to retrieve the data as ``bytes`` in these
cases.
- ``SSL_ENGINES`` and ``INFO_COOKIELIST`` return a list of strings.
The same encoding caveats apply; use :ref:`getinfo_raw `
to retrieve the
data as a list of byte strings.
- ``INFO_CERTINFO`` returns a list with one element
per certificate in the chain, starting with the leaf; each element is a
sequence of *(key, value)* tuples where both ``key`` and ``value`` are
strings. String encoding caveats apply; use :ref:`getinfo_raw `
to retrieve
certificate data as byte strings.
On Python 2, ``getinfo`` and ``getinfo_raw`` behave identically.
Example usage::
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.OPT_CERTINFO, 1)
c.setopt(pycurl.URL, "https://python.org")
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.perform()
print(c.getinfo(pycurl.HTTP_CODE))
# --> 200
print(c.getinfo(pycurl.EFFECTIVE_URL))
# --> "https://www.python.org/"
certinfo = c.getinfo(pycurl.INFO_CERTINFO)
print(certinfo)
# --> [(('Subject', 'C = AU, ST = Some-State, O = PycURL test suite,
CN = localhost'), ('Issuer', 'C = AU, ST = Some-State,
O = PycURL test suite, OU = localhost, CN = localhost'),
('Version', '0'), ...)]
Raises pycurl.error exception upon failure.
.. _curl_easy_getinfo:
https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html
pycurl-7.43.0.2/doc/docstrings/curl_errstr_raw.rst 0000644 0001750 0001750 00000000674 13301165576 021222 0 ustar me me 0000000 0000000 errstr_raw() -> byte string
Return the internal libcurl error buffer of this handle as a byte string.
Return value is a ``str`` instance on Python 2 and ``bytes`` instance
on Python 3. Unlike :ref:`errstr_raw `, ``errstr_raw``
allows reading libcurl error buffer in Python 3 when its contents is not
valid in Python's default encoding.
On Python 2, ``errstr`` and ``errstr_raw`` behave identically.
*Added in version 7.43.0.2.*
pycurl-7.43.0.2/doc/docstrings/curl_setopt_string.rst 0000644 0001750 0001750 00000002324 13211045165 021715 0 ustar me me 0000000 0000000 setopt_string(option, value) -> None
Set curl session option to a string value.
This method allows setting string options that are not officially supported
by PycURL, for example because they did not exist when the version of PycURL
being used was released.
:py:meth:`pycurl.Curl.setopt` should be used for setting options that
PycURL knows about.
**Warning:** No checking is performed that *option* does, in fact,
expect a string value. Using this method incorrectly can crash the program
and may lead to a security vulnerability.
Furthermore, it is on the application to ensure that the *value* object
does not get garbage collected while libcurl is using it.
libcurl copies most string options but not all; one option whose value
is not copied by libcurl is `CURLOPT_POSTFIELDS`_.
*option* would generally need to be given as an integer literal rather than
a symbolic constant.
*value* can be a binary string or a Unicode string using ASCII code points,
same as with string options given to PycURL elsewhere.
Example setting URL via ``setopt_string``::
import pycurl
c = pycurl.Curl()
c.setopt_string(10002, "http://www.python.org/")
.. _CURLOPT_POSTFIELDS: https://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html
pycurl-7.43.0.2/doc/docstrings/multi_add_handle.rst 0000644 0001750 0001750 00000001012 13300711050 021222 0 ustar me me 0000000 0000000 add_handle(Curl object) -> None
Corresponds to `curl_multi_add_handle`_ in libcurl. This method adds an
existing and valid Curl object to the CurlMulti object.
*Changed in version 7.43.0.2:* add_handle now ensures that the Curl object
is not garbage collected while it is being used by a CurlMulti object.
Previously application had to maintain an outstanding reference to the Curl
object to keep it from being garbage collected.
.. _curl_multi_add_handle:
https://curl.haxx.se/libcurl/c/curl_multi_add_handle.html
pycurl-7.43.0.2/doc/docstrings/multi_fdset.rst 0000644 0001750 0001750 00000001604 13211045165 020303 0 ustar me me 0000000 0000000 fdset() -> tuple of lists with active file descriptors, readable, writeable, exceptions
Returns a tuple of three lists that can be passed to the select.select() method.
Corresponds to `curl_multi_fdset`_ in libcurl. This method extracts the
file descriptor information from a CurlMulti object. The returned lists can
be used with the ``select`` module to poll for events.
Example usage::
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, "https://curl.haxx.se")
m = pycurl.CurlMulti()
m.add_handle(c)
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM: break
while num_handles:
apply(select.select, m.fdset() + (1,))
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM: break
.. _curl_multi_fdset:
https://curl.haxx.se/libcurl/c/curl_multi_fdset.html
pycurl-7.43.0.2/doc/docstrings/curl_errstr.rst 0000644 0001750 0001750 00000000721 13301165576 020342 0 ustar me me 0000000 0000000 errstr() -> string
Return the internal libcurl error buffer of this handle as a string.
Return value is a ``str`` instance on all Python versions.
On Python 3, error buffer data is decoded using Python's default encoding
at the time of the call. If this decoding fails, ``UnicodeDecodeError`` is
raised. Use :ref:`errstr_raw ` to retrieve the error buffer
as a byte string in this case.
On Python 2, ``errstr`` and ``errstr_raw`` behave identically.
pycurl-7.43.0.2/doc/docstrings/share_close.rst 0000644 0001750 0001750 00000000471 13211045165 020254 0 ustar me me 0000000 0000000 close() -> None
Close shared handle.
Corresponds to `curl_share_cleanup`_ in libcurl. This method is
automatically called by pycurl when a CurlShare object no longer has
any references to it, but can also be called explicitly.
.. _curl_share_cleanup:
https://curl.haxx.se/libcurl/c/curl_share_cleanup.html
pycurl-7.43.0.2/doc/docstrings/pycurl_global_cleanup.rst 0000644 0001750 0001750 00000000271 13211045165 022330 0 ustar me me 0000000 0000000 global_cleanup() -> None
Cleanup curl environment.
Corresponds to `curl_global_cleanup`_ in libcurl.
.. _curl_global_cleanup: https://curl.haxx.se/libcurl/c/curl_global_cleanup.html
pycurl-7.43.0.2/doc/docstrings/multi_select.rst 0000644 0001750 0001750 00000001336 13211045165 020457 0 ustar me me 0000000 0000000 select([timeout]) -> number of ready file descriptors or -1 on timeout
Returns result from doing a select() on the curl multi file descriptor
with the given timeout.
This is a convenience function which simplifies the combined use of
``fdset()`` and the ``select`` module.
Example usage::
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, "https://curl.haxx.se")
m = pycurl.CurlMulti()
m.add_handle(c)
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM: break
while num_handles:
ret = m.select(1.0)
if ret == -1: continue
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM: break
pycurl-7.43.0.2/doc/docstrings/curl_reset.rst 0000644 0001750 0001750 00000000424 13211045165 020132 0 ustar me me 0000000 0000000 reset() -> None
Reset all options set on curl handle to default values, but preserves
live connections, session ID cache, DNS cache, cookies, and shares.
Corresponds to `curl_easy_reset`_ in libcurl.
.. _curl_easy_reset: https://curl.haxx.se/libcurl/c/curl_easy_reset.html
pycurl-7.43.0.2/doc/docstrings/pycurl_version_info.rst 0000644 0001750 0001750 00000001220 13211045165 022054 0 ustar me me 0000000 0000000 version_info() -> tuple
Returns a 12-tuple with the version info.
Corresponds to `curl_version_info`_ in libcurl. Returns a tuple of
information which is similar to the ``curl_version_info_data`` struct
returned by ``curl_version_info()`` in libcurl.
Example usage::
>>> import pycurl
>>> pycurl.version_info()
(3, '7.33.0', 467200, 'amd64-portbld-freebsd9.1', 33436, 'OpenSSL/0.9.8x',
0, '1.2.7', ('dict', 'file', 'ftp', 'ftps', 'gopher', 'http', 'https',
'imap', 'imaps', 'pop3', 'pop3s', 'rtsp', 'smtp', 'smtps', 'telnet',
'tftp'), None, 0, None)
.. _curl_version_info: https://curl.haxx.se/libcurl/c/curl_version_info.html
pycurl-7.43.0.2/doc/docstrings/share.rst 0000644 0001750 0001750 00000000352 13211045142 017060 0 ustar me me 0000000 0000000 CurlShare() -> New CurlShare object
Creates a new :ref:`curlshareobject` which corresponds to a
``CURLSH`` handle in libcurl. CurlShare objects is what you pass as an
argument to the SHARE option on :ref:`Curl objects `.
pycurl-7.43.0.2/doc/docstrings/multi_socket_action.rst 0000644 0001750 0001750 00000000445 13211045165 022025 0 ustar me me 0000000 0000000 socket_action(sockfd, ev_bitmask) -> tuple
Returns result from doing a socket_action() on the curl multi file descriptor
with the given timeout.
Corresponds to `curl_multi_socket_action`_ in libcurl.
.. _curl_multi_socket_action: https://curl.haxx.se/libcurl/c/curl_multi_socket_action.html
pycurl-7.43.0.2/doc/docstrings/multi_remove_handle.rst 0000644 0001750 0001750 00000000663 13211045165 022012 0 ustar me me 0000000 0000000 remove_handle(Curl object) -> None
Corresponds to `curl_multi_remove_handle`_ in libcurl. This method
removes an existing and valid Curl object from the CurlMulti object.
IMPORTANT NOTE: remove_handle does not implicitly remove a Python reference
from the Curl object (and thus does not decrease the reference count on the
Curl object).
.. _curl_multi_remove_handle:
https://curl.haxx.se/libcurl/c/curl_multi_remove_handle.html
pycurl-7.43.0.2/doc/docstrings/multi_timeout.rst 0000644 0001750 0001750 00000000312 13211045165 020657 0 ustar me me 0000000 0000000 timeout() -> int
Returns how long to wait for action before proceeding.
Corresponds to `curl_multi_timeout`_ in libcurl.
.. _curl_multi_timeout: https://curl.haxx.se/libcurl/c/curl_multi_timeout.html
pycurl-7.43.0.2/doc/docstrings/curl_perform.rst 0000644 0001750 0001750 00000000334 13211045165 020462 0 ustar me me 0000000 0000000 perform() -> None
Perform a file transfer.
Corresponds to `curl_easy_perform`_ in libcurl.
Raises pycurl.error exception upon failure.
.. _curl_easy_perform:
https://curl.haxx.se/libcurl/c/curl_easy_perform.html
pycurl-7.43.0.2/doc/docstrings/multi_perform.rst 0000644 0001750 0001750 00000000311 13211045165 020642 0 ustar me me 0000000 0000000 perform() -> tuple of status and the number of active Curl objects
Corresponds to `curl_multi_perform`_ in libcurl.
.. _curl_multi_perform:
https://curl.haxx.se/libcurl/c/curl_multi_perform.html
pycurl-7.43.0.2/doc/docstrings/multi_setopt.rst 0000644 0001750 0001750 00000002636 13211045165 020522 0 ustar me me 0000000 0000000 setopt(option, value) -> None
Set curl multi option. Corresponds to `curl_multi_setopt`_ in libcurl.
*option* specifies which option to set. PycURL defines constants
corresponding to ``CURLMOPT_*`` constants in libcurl, except that
the ``CURLMOPT_`` prefix is replaced with ``M_`` prefix.
For example, ``CURLMOPT_PIPELINING`` is
exposed in PycURL as ``pycurl.M_PIPELINING``. For convenience, ``CURLMOPT_*``
constants are also exposed on CurlMulti objects::
import pycurl
m = pycurl.CurlMulti()
m.setopt(pycurl.M_PIPELINING, 1)
# Same as:
m.setopt(m.M_PIPELINING, 1)
*value* specifies the value to set the option to. Different options accept
values of different types:
- Options specified by `curl_multi_setopt`_ as accepting ``1`` or an
integer value accept Python integers, long integers (on Python 2.x) and
booleans::
m.setopt(pycurl.M_PIPELINING, True)
m.setopt(pycurl.M_PIPELINING, 1)
# Python 2.x only:
m.setopt(pycurl.M_PIPELINING, 1L)
- ``*FUNCTION`` options accept a function. Supported callbacks are
``CURLMOPT_SOCKETFUNCTION`` AND ``CURLMOPT_TIMERFUNCTION``. Please refer to
the PycURL test suite for examples on using the callbacks.
Raises TypeError when the option value is not of a type accepted by the
respective option, and pycurl.error exception when libcurl rejects the
option or its value.
.. _curl_multi_setopt: https://curl.haxx.se/libcurl/c/curl_multi_setopt.html
pycurl-7.43.0.2/doc/docstrings/curl_perform_rb.rst 0000644 0001750 0001750 00000001273 13301332107 021143 0 ustar me me 0000000 0000000 perform_rb() -> response_body
Perform a file transfer and return response body as a byte string.
This method arranges for response body to be saved in a StringIO
(Python 2) or BytesIO (Python 3) instance, then invokes :ref:`perform `
to perform the file transfer, then returns the value of the StringIO/BytesIO
instance which is a ``str`` instance on Python 2 and ``bytes`` instance
on Python 3. Errors during transfer raise ``pycurl.error`` exceptions
just like in :ref:`perform `.
Use :ref:`perform_rs ` to retrieve response body as a string
(``str`` instance on both Python 2 and 3).
Raises ``pycurl.error`` exception upon failure.
*Added in version 7.43.0.2.*
pycurl-7.43.0.2/doc/docstrings/multi_socket_all.rst 0000644 0001750 0001750 00000000173 13211045142 021311 0 ustar me me 0000000 0000000 socket_all() -> Tuple.
Returns result from doing a socket_all() on the curl multi file descriptor
with the given timeout.
pycurl-7.43.0.2/doc/docstrings/multi_assign.rst 0000644 0001750 0001750 00000000413 13211045165 020457 0 ustar me me 0000000 0000000 assign(sockfd, object) -> None
Creates an association in the multi handle between the given socket and
a private object in the application.
Corresponds to `curl_multi_assign`_ in libcurl.
.. _curl_multi_assign: https://curl.haxx.se/libcurl/c/curl_multi_assign.html
pycurl-7.43.0.2/doc/docstrings/multi_close.rst 0000644 0001750 0001750 00000000443 13211045165 020303 0 ustar me me 0000000 0000000 close() -> None
Corresponds to `curl_multi_cleanup`_ in libcurl. This method is
automatically called by pycurl when a CurlMulti object no longer has any
references to it, but can also be called explicitly.
.. _curl_multi_cleanup:
https://curl.haxx.se/libcurl/c/curl_multi_cleanup.html
pycurl-7.43.0.2/doc/docstrings/curl_getinfo_raw.rst 0000644 0001750 0001750 00000006005 13301167757 021331 0 ustar me me 0000000 0000000 getinfo_raw(option) -> Result
Extract and return information from a curl session,
returning string data as byte strings.
Corresponds to `curl_easy_getinfo`_ in libcurl.
The ``getinfo_raw`` method should not be called unless
``perform`` has been called and finished.
*option* is a constant corresponding to one of the
``CURLINFO_*`` constants in libcurl. Most option constant names match
the respective ``CURLINFO_*`` constant names with the ``CURLINFO_`` prefix
removed, for example ``CURLINFO_CONTENT_TYPE`` is accessible as
``pycurl.CONTENT_TYPE``. Exceptions to this rule are as follows:
- ``CURLINFO_FILETIME`` is mapped as ``pycurl.INFO_FILETIME``
- ``CURLINFO_COOKIELIST`` is mapped as ``pycurl.INFO_COOKIELIST``
- ``CURLINFO_CERTINFO`` is mapped as ``pycurl.INFO_CERTINFO``
- ``CURLINFO_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.INFO_RTSP_CLIENT_CSEQ``
- ``CURLINFO_RTSP_CSEQ_RECV`` is mapped as ``pycurl.INFO_RTSP_CSEQ_RECV``
- ``CURLINFO_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.INFO_RTSP_SERVER_CSEQ``
- ``CURLINFO_RTSP_SESSION_ID`` is mapped as ``pycurl.INFO_RTSP_SESSION_ID``
The type of return value depends on the option, as follows:
- Options documented by libcurl to return an integer value return a
Python integer (``long`` on Python 2, ``int`` on Python 3).
- Options documented by libcurl to return a floating point value
return a Python ``float``.
- Options documented by libcurl to return a string value
return a Python byte string (``str`` on Python 2, ``bytes`` on Python 3).
The string contains whatever data libcurl returned.
Use :ref:`getinfo ` to retrieve this data as a Unicode string on Python 3.
- ``SSL_ENGINES`` and ``INFO_COOKIELIST`` return a list of byte strings.
The same encoding caveats apply; use :ref:`getinfo ` to retrieve the
data as a list of potentially Unicode strings.
- ``INFO_CERTINFO`` returns a list with one element
per certificate in the chain, starting with the leaf; each element is a
sequence of *(key, value)* tuples where both ``key`` and ``value`` are
byte strings. String encoding caveats apply; use :ref:`getinfo `
to retrieve
certificate data as potentially Unicode strings.
On Python 2, ``getinfo`` and ``getinfo_raw`` behave identically.
Example usage::
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.OPT_CERTINFO, 1)
c.setopt(pycurl.URL, "https://python.org")
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.perform()
print(c.getinfo_raw(pycurl.HTTP_CODE))
# --> 200
print(c.getinfo_raw(pycurl.EFFECTIVE_URL))
# --> b"https://www.python.org/"
certinfo = c.getinfo_raw(pycurl.INFO_CERTINFO)
print(certinfo)
# --> [((b'Subject', b'C = AU, ST = Some-State, O = PycURL test suite,
CN = localhost'), (b'Issuer', b'C = AU, ST = Some-State,
O = PycURL test suite, OU = localhost, CN = localhost'),
(b'Version', b'0'), ...)]
Raises pycurl.error exception upon failure.
*Added in version 7.43.0.2.*
.. _curl_easy_getinfo:
https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html
pycurl-7.43.0.2/doc/docstrings/curl_close.rst 0000644 0001750 0001750 00000000477 13211045165 020125 0 ustar me me 0000000 0000000 close() -> None
Close handle and end curl session.
Corresponds to `curl_easy_cleanup`_ in libcurl. This method is
automatically called by pycurl when a Curl object no longer has any
references to it, but can also be called explicitly.
.. _curl_easy_cleanup:
https://curl.haxx.se/libcurl/c/curl_easy_cleanup.html
pycurl-7.43.0.2/doc/docstrings/curl_setopt.rst 0000644 0001750 0001750 00000010757 13301167757 020354 0 ustar me me 0000000 0000000 setopt(option, value) -> None
Set curl session option. Corresponds to `curl_easy_setopt`_ in libcurl.
*option* specifies which option to set. PycURL defines constants
corresponding to ``CURLOPT_*`` constants in libcurl, except that
the ``CURLOPT_`` prefix is removed. For example, ``CURLOPT_URL`` is
exposed in PycURL as ``pycurl.URL``, with some exceptions as detailed below.
For convenience, ``CURLOPT_*``
constants are also exposed on the Curl objects themselves::
import pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://www.python.org/")
# Same as:
c.setopt(c.URL, "http://www.python.org/")
The following are exceptions to option constant naming convention:
- ``CURLOPT_FILETIME`` is mapped as ``pycurl.OPT_FILETIME``
- ``CURLOPT_CERTINFO`` is mapped as ``pycurl.OPT_CERTINFO``
- ``CURLOPT_COOKIELIST`` is mapped as ``pycurl.COOKIELIST``
and, as of PycURL 7.43.0.2, also as ``pycurl.OPT_COOKIELIST``
- ``CURLOPT_RTSP_CLIENT_CSEQ`` is mapped as ``pycurl.OPT_RTSP_CLIENT_CSEQ``
- ``CURLOPT_RTSP_REQUEST`` is mapped as ``pycurl.OPT_RTSP_REQUEST``
- ``CURLOPT_RTSP_SERVER_CSEQ`` is mapped as ``pycurl.OPT_RTSP_SERVER_CSEQ``
- ``CURLOPT_RTSP_SESSION_ID`` is mapped as ``pycurl.OPT_RTSP_SESSION_ID``
- ``CURLOPT_RTSP_STREAM_URI`` is mapped as ``pycurl.OPT_RTSP_STREAM_URI``
- ``CURLOPT_RTSP_TRANSPORT`` is mapped as ``pycurl.OPT_RTSP_TRANSPORT``
*value* specifies the value to set the option to. Different options accept
values of different types:
- Options specified by `curl_easy_setopt`_ as accepting ``1`` or an
integer value accept Python integers, long integers (on Python 2.x) and
booleans::
c.setopt(pycurl.FOLLOWLOCATION, True)
c.setopt(pycurl.FOLLOWLOCATION, 1)
# Python 2.x only:
c.setopt(pycurl.FOLLOWLOCATION, 1L)
- Options specified as accepting strings by ``curl_easy_setopt`` accept
byte strings (``str`` on Python 2, ``bytes`` on Python 3) and
Unicode strings with ASCII code points only.
For more information, please refer to :ref:`unicode`. Example::
c.setopt(pycurl.URL, "http://www.python.org/")
c.setopt(pycurl.URL, u"http://www.python.org/")
# Python 3.x only:
c.setopt(pycurl.URL, b"http://www.python.org/")
- ``HTTP200ALIASES``, ``HTTPHEADER``, ``POSTQUOTE``, ``PREQUOTE``,
``PROXYHEADER`` and
``QUOTE`` accept a list or tuple of strings. The same rules apply to these
strings as do to string option values. Example::
c.setopt(pycurl.HTTPHEADER, ["Accept:"])
c.setopt(pycurl.HTTPHEADER, ("Accept:",))
- ``READDATA`` accepts a file object or any Python object which has
a ``read`` method. On Python 2, a file object will be passed directly
to libcurl and may result in greater transfer efficiency, unless
PycURL has been compiled with ``AVOID_STDIO`` option.
On Python 3 and on Python 2 when the value is not a true file object,
``READDATA`` is emulated in PycURL via ``READFUNCTION``.
The file should generally be opened in binary mode. Example::
f = open('file.txt', 'rb')
c.setopt(c.READDATA, f)
- ``WRITEDATA`` and ``WRITEHEADER`` accept a file object or any Python
object which has a ``write`` method. On Python 2, a file object will
be passed directly to libcurl and may result in greater transfer efficiency,
unless PycURL has been compiled with ``AVOID_STDIO`` option.
On Python 3 and on Python 2 when the value is not a true file object,
``WRITEDATA`` is emulated in PycURL via ``WRITEFUNCTION``.
The file should generally be opened in binary mode. Example::
f = open('/dev/null', 'wb')
c.setopt(c.WRITEDATA, f)
- ``*FUNCTION`` options accept a function. Supported callbacks are documented
in :ref:`callbacks`. Example::
# Python 2
import StringIO
b = StringIO.StringIO()
c.setopt(pycurl.WRITEFUNCTION, b.write)
- ``SHARE`` option accepts a :ref:`curlshareobject`.
It is possible to set integer options - and only them - that PycURL does
not know about by using the numeric value of the option constant directly.
For example, ``pycurl.VERBOSE`` has the value 42, and may be set as follows::
c.setopt(42, 1)
*setopt* can reset some options to their default value, performing the job of
:py:meth:`pycurl.Curl.unsetopt`, if ``None`` is passed
for the option value. The following two calls are equivalent::
c.setopt(c.URL, None)
c.unsetopt(c.URL)
Raises TypeError when the option value is not of a type accepted by the
respective option, and pycurl.error exception when libcurl rejects the
option or its value.
.. _curl_easy_setopt: https://curl.haxx.se/libcurl/c/curl_easy_setopt.html
pycurl-7.43.0.2/doc/docstrings/curl_set_ca_certs.rst 0000644 0001750 0001750 00000000220 13211045165 021440 0 ustar me me 0000000 0000000 set_ca_certs() -> None
Load ca certs from provided unicode string.
Note that certificates will be added only when cURL starts new connection.
pycurl-7.43.0.2/doc/docstrings/multi.rst 0000644 0001750 0001750 00000000176 13211045142 017114 0 ustar me me 0000000 0000000 CurlMulti() -> New CurlMulti object
Creates a new :ref:`curlmultiobject` which corresponds to
a ``CURLM`` handle in libcurl.
pycurl-7.43.0.2/doc/curl.rst 0000644 0001750 0001750 00000000240 13211045142 014540 0 ustar me me 0000000 0000000 curl Module Functionality
=========================
.. automodule:: curl
High Level Curl Object
----------------------
.. autoclass:: curl.Curl
:members:
pycurl-7.43.0.2/doc/unicode.rst 0000644 0001750 0001750 00000022417 13211045161 015234 0 ustar me me 0000000 0000000 .. _unicode:
String And Unicode Handling
===========================
Generally speaking, libcurl does not perform data encoding or decoding.
In particular, libcurl is not Unicode-aware, but operates on byte streams.
libcurl leaves it up to the application - PycURL library or an application
using PycURL in this case - to encode and decode Unicode data into byte streams.
PycURL, being a thin wrapper around libcurl, generally does not perform
this encoding and decoding either, leaving it up to the application.
Specifically:
- Data that PycURL passes to an application, such as via callback functions,
is normally byte strings. The application must decode them to obtain text
(Unicode) data.
- Data that an application passes to PycURL, such as via ``setopt`` calls,
must normally be byte strings appropriately encoded. For convenience and
compatibility with existing code, PycURL will accept Unicode strings that
contain ASCII code points only [#ascii]_, and transparently encode these to
byte strings.
Why doesn't PycURL automatically encode and decode, say, HTTP request or
response data? The key to remember is that libcurl supports over 20 protocols,
and PycURL generally has no knowledge of what protocol is being used by
a particular request as PycURL does not track application state. Having
to manually encode and decode data is unfortunately the price of libcurl's
flexibility.
Setting Options - Python 2.x
----------------------------
Under Python 2, the ``str`` type can hold arbitrary encoded byte strings.
PycURL will pass whatever byte strings it is given verbatim to libcurl.
The following code will work::
>>> import pycurl
>>> c = pycurl.Curl()
>>> c.setopt(c.USERAGENT, 'Foo\xa9')
# ok
Unicode strings can be used but must contain ASCII code points only::
>>> c.setopt(c.USERAGENT, u'Foo')
# ok
>>> c.setopt(c.USERAGENT, u'Foo\xa9')
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa9' in position 3: ordinal not in range(128)
>>> c.setopt(c.USERAGENT, u'Foo\xa9'.encode('iso-8859-1'))
# ok
Setting Options - Python 3.x
----------------------------
Under Python 3, the ``bytes`` type holds arbitrary encoded byte strings.
PycURL will accept ``bytes`` values for all options where libcurl specifies
a "string" argument::
>>> import pycurl
>>> c = pycurl.Curl()
>>> c.setopt(c.USERAGENT, b'Foo\xa9')
# ok
The ``str`` type holds Unicode data. PycURL will accept ``str`` values
containing ASCII code points only::
>>> c.setopt(c.USERAGENT, 'Foo')
# ok
>>> c.setopt(c.USERAGENT, 'Foo\xa9')
Traceback (most recent call last):
File "", line 1, in
UnicodeEncodeError: 'ascii' codec can't encode character '\xa9' in position 3: ordinal not in range(128)
>>> c.setopt(c.USERAGENT, 'Foo\xa9'.encode('iso-8859-1'))
# ok
Writing To Files
----------------
PycURL will return all data read from the network as byte strings. On Python 2,
this means the write callbacks will receive ``str`` objects, and
on Python 3, write callbacks will receive ``bytes`` objects.
Under Python 2, when using e.g. ``WRITEDATA`` or ``WRITEFUNCTION`` options,
files being written to *should* be opened in binary mode. Writing to files
opened in text mode will not raise exceptions but may corrupt data.
Under Python 3, PycURL passes strings and binary data to the application
using ``bytes`` instances. When writing to files, the files must be opened
in binary mode for the writes to work::
import pycurl
c = pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
# File opened in binary mode.
with open('/dev/null','wb') as f:
c.setopt(c.WRITEDATA, f)
# Same result if using WRITEFUNCTION instead:
#c.setopt(c.WRITEFUNCTION, f.write)
c.perform()
# ok
If a file is opened in text mode (``w`` instead of ``wb`` mode), an error
similar to the following will result::
TypeError: must be str, not bytes
Traceback (most recent call last):
File "/tmp/test.py", line 8, in
c.perform()
pycurl.error: (23, 'Failed writing body (0 != 168)')
The TypeError is actually an exception raised by Python which will be printed,
but not propagated, by PycURL. PycURL will raise a ``pycurl.error`` to
signify operation failure.
Writing To StringIO/BytesIO
---------------------------
Under Python 2, response can be saved in memory by using a ``StringIO``
object::
import pycurl
from StringIO import StringIO
c = pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
buffer = StringIO()
c.setopt(c.WRITEDATA, buffer)
# Same result if using WRITEFUNCTION instead:
#c.setopt(c.WRITEFUNCTION, buffer.write)
c.perform()
# ok
Under Python 3, as PycURL invokes the write callback with ``bytes`` argument,
the response must be written to a ``BytesIO`` object::
import pycurl
from io import BytesIO
c = pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
buffer = BytesIO()
c.setopt(c.WRITEDATA, buffer)
# Same result if using WRITEFUNCTION instead:
#c.setopt(c.WRITEFUNCTION, buffer.write)
c.perform()
# ok
Attempting to use a ``StringIO`` object will produce an error::
import pycurl
from io import StringIO
c = pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
buffer = StringIO()
c.setopt(c.WRITEDATA, buffer)
c.perform()
TypeError: string argument expected, got 'bytes'
Traceback (most recent call last):
File "/tmp/test.py", line 9, in
c.perform()
pycurl.error: (23, 'Failed writing body (0 != 168)')
The following idiom can be used for code that needs to be compatible with both
Python 2 and Python 3::
import pycurl
try:
# Python 3
from io import BytesIO
except ImportError:
# Python 2
from StringIO import StringIO as BytesIO
c = pycurl.Curl()
c.setopt(c.URL,'http://pycurl.io')
buffer = BytesIO()
c.setopt(c.WRITEDATA, buffer)
c.perform()
# ok
# Decode the response body:
string_body = buffer.getvalue().decode('utf-8')
Header Functions
----------------
Although headers are often ASCII text, they are still returned as
``bytes`` instances on Python 3 and thus require appropriate decoding.
HTTP headers are encoded in ISO/IEC 8859-1 according to the standards.
When using ``WRITEHEADER`` option to write headers to files, the files
should be opened in binary mode in Python 2 and must be opened in binary
mode in Python 3, same as with ``WRITEDATA``.
Read Functions
--------------
Read functions are expected to provide data in the same fashion as
string options expect it:
- On Python 2, the data can be given as ``str`` instances, appropriately
encoded.
- On Python 2, the data can be given as ``unicode`` instances containing
ASCII code points only.
- On Python 3, the data can be given as ``bytes`` instances.
- On Python 3. the data can be given as ``str`` instances containing
ASCII code points only.
Caution: when using CURLOPT_READFUNCTION in tandem with CURLOPT_POSTFIELDSIZE,
as would be done for HTTP for example, take care to pass the length of
*encoded* data to CURLOPT_POSTFIELDSIZE if you are performing the encoding.
If you pass the number of Unicode characters rather than
encoded bytes to libcurl, the server will receive wrong Content-Length.
Alternatively you can return Unicode strings from a CURLOPT_READFUNCTION
function, if your data contains only ASCII code points,
and let PycURL encode them for you.
How PycURL Handles Unicode Strings
----------------------------------
If PycURL is given a Unicode string which contains non-ASCII code points,
and as such cannot be encoded to ASCII, PycURL will return an error to libcurl,
and libcurl in turn will fail the request with an error like
"read function error/data error". PycURL will then raise ``pycurl.error``
with this latter message. The encoding exception that was the
underlying cause of the problem is stored as ``sys.last_value``.
Figuring Out Correct Encoding
-----------------------------
What encoding should be used when is a complicated question. For example,
when working with HTTP:
- URLs and POSTFIELDS data must be URL-encoded. A URL-encoded string has
only ASCII code points.
- Headers must be ISO/IEC 8859-1 encoded.
- Encoding for bodies is specified in Content-Type and Content-Encoding headers.
Legacy PycURL Versions
----------------------
The Unicode handling documented here was implemented in PycURL 7.19.3
along with Python 3 support. Prior to PycURL 7.19.3 Unicode data was not
accepted at all::
>>> import pycurl
>>> c = pycurl.Curl()
>>> c.setopt(c.USERAGENT, u'Foo\xa9')
Traceback (most recent call last):
File "", line 1, in
TypeError: invalid arguments to setopt
Some GNU/Linux distributions provided Python 3 packages of PycURL prior to
PycURL 7.19.3. These packages included unofficial patches
([#patch1]_, [#patch2]_) which did not handle Unicode correctly, and did not behave
as described in this document. Such unofficial versions of PycURL should
be avoided.
.. rubric:: Footnotes
.. [#ascii] Only ASCII is accepted; ISO-8859-1/Latin 1, for example, will be
rejected.
.. [#patch1] http://sourceforge.net/p/pycurl/patches/5/
.. [#patch2] http://sourceforge.net/p/pycurl/patches/12/
pycurl-7.43.0.2/doc/curlshareobject.rst 0000644 0001750 0001750 00000000345 13211045142 016760 0 ustar me me 0000000 0000000 .. _curlshareobject:
CurlShare Object
================
.. autoclass:: pycurl.CurlShare
CurlShare objects have the following methods:
.. automethod:: pycurl.CurlShare.close
.. automethod:: pycurl.CurlShare.setopt
pycurl-7.43.0.2/doc/thread-safety.rst 0000644 0001750 0001750 00000002604 13211045165 016346 0 ustar me me 0000000 0000000 .. _thread-safety:
Thread Safety
=============
Per `libcurl thread safety documentation`_, libcurl is thread-safe but
has no internal thread synchronization.
For Python programs using PycURL, this means:
* Accessing the same PycURL object from different threads is OK when
this object is not involved in active transfers, as Python internally
has a Global Interpreter Lock and only one operating system thread can
be executing Python code at a time.
* Accessing a PycURL object that is involved in an active transfer from
Python code *inside a libcurl callback for the PycURL object in question*
is OK, because PycURL takes out the appropriate locks.
* Accessing a PycURL object that is involved in an active transfer from
Python code *outside of a libcurl callback for the PycURL object in question*
is unsafe.
PycURL handles the necessary SSL locks for OpenSSL/LibreSSL, GnuTLS and NSS.
A special situation exists when libcurl uses the standard C library
name resolver (i.e., not threaded nor c-ares resolver). By default libcurl
uses signals for timeouts with the C library resolver, and signals do not
work properly in multi-threaded programs. When using PycURL objects from
multiple Python threads ``NOSIGNAL`` option `must be given`_.
.. _libcurl thread safety documentation: https://curl.haxx.se/libcurl/c/threadsafe.html
.. _must be given: https://github.com/curl/curl/issues/1003
pycurl-7.43.0.2/doc/static/ 0000755 0001750 0001750 00000000000 13304422066 014343 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/doc/static/favicon.ico 0000644 0001750 0001750 00000000476 13211045142 016464 0 ustar me me 0000000 0000000 ( ( pwww p pp pp pp pp pp wpww p p wpp pp p p pycurl-7.43.0.2/doc/callbacks.rst 0000644 0001750 0001750 00000034310 13277627465 015551 0 ustar me me 0000000 0000000 .. _callbacks:
Callbacks
=========
For more fine-grained control, libcurl allows a number of callbacks to be
associated with each connection. In pycurl, callbacks are defined using the
``setopt()`` method for Curl objects with options ``WRITEFUNCTION``,
``READFUNCTION``, ``HEADERFUNCTION``, ``PROGRESSFUNCTION``,
``XFERINFOFUNCTION``, ``IOCTLFUNCTION``, or
``DEBUGFUNCTION``. These options correspond to the libcurl options with ``CURLOPT_``
prefix removed. A callback in pycurl must be either a regular Python
function, a class method or an extension type function.
There are some limitations to some of the options which can be used
concurrently with the pycurl callbacks compared to the libcurl callbacks.
This is to allow different callback functions to be associated with different
Curl objects. More specifically, ``WRITEDATA`` cannot be used with
``WRITEFUNCTION``, ``READDATA`` cannot be used with ``READFUNCTION``,
``WRITEHEADER`` cannot be used with ``HEADERFUNCTION``.
In practice, these limitations can be overcome by having a
callback function be a class instance method and rather use the class
instance attributes to store per object data such as files used in the
callbacks.
The signature of each callback used in PycURL is documented below.
Error Reporting
---------------
PycURL callbacks are invoked as follows:
Python application -> ``perform()`` -> libcurl (C code) -> Python callback
Because callbacks are invoked by libcurl, they should not raise exceptions
on failure but instead return appropriate values indicating failure.
The documentation for individual callbacks below specifies expected success and
failure return values.
Unhandled exceptions propagated out of Python callbacks will be intercepted
by PycURL or the Python runtime. This will fail the callback with a
generic failure status, in turn failing the ``perform()`` operation.
A failing ``perform()`` will raise ``pycurl.error``, but the error code
used depends on the specific callback.
Rich context information like exception objects can be stored in various ways,
for example the following example stores OPENSOCKET callback exception on the
Curl object::
import pycurl, random, socket
class ConnectionRejected(Exception):
pass
def opensocket(curl, purpose, curl_address):
# always fail
curl.exception = ConnectionRejected('Rejecting connection attempt in opensocket callback')
return pycurl.SOCKET_BAD
# the callback must create a socket if it does not fail,
# see examples/opensocketexception.py
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io')
c.exception = None
c.setopt(c.OPENSOCKETFUNCTION,
lambda purpose, address: opensocket(c, purpose, address))
try:
c.perform()
except pycurl.error as e:
if e.args[0] == pycurl.E_COULDNT_CONNECT and c.exception:
print(c.exception)
else:
print(e)
WRITEFUNCTION
-------------
.. function:: WRITEFUNCTION(byte string) -> number of characters written
Callback for writing data. Corresponds to `CURLOPT_WRITEFUNCTION`_
in libcurl.
On Python 3, the argument is of type ``bytes``.
The ``WRITEFUNCTION`` callback may return the number of bytes written.
If this number is not equal to the size of the byte string, this signifies
an error and libcurl will abort the request. Returning ``None`` is an
alternate way of indicating that the callback has consumed all of the
string passed to it and, hence, succeeded.
`write_test.py test`_ shows how to use ``WRITEFUNCTION``.
Example: Callbacks for document header and body
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This example prints the header data to stderr and the body data to stdout.
Also note that neither callback returns the number of bytes written. For
WRITEFUNCTION and HEADERFUNCTION callbacks, returning None implies that all
bytes where written.
::
## Callback function invoked when body data is ready
def body(buf):
# Print body data to stdout
import sys
sys.stdout.write(buf)
# Returning None implies that all bytes were written
## Callback function invoked when header data is ready
def header(buf):
# Print header data to stderr
import sys
sys.stderr.write(buf)
# Returning None implies that all bytes were written
c = pycurl.Curl()
c.setopt(pycurl.URL, "http://www.python.org/")
c.setopt(pycurl.WRITEFUNCTION, body)
c.setopt(pycurl.HEADERFUNCTION, header)
c.perform()
HEADERFUNCTION
--------------
.. function:: HEADERFUNCTION(byte string) -> number of characters written
Callback for writing received headers. Corresponds to
`CURLOPT_HEADERFUNCTION`_ in libcurl.
On Python 3, the argument is of type ``bytes``.
The ``HEADERFUNCTION`` callback may return the number of bytes written.
If this number is not equal to the size of the byte string, this signifies
an error and libcurl will abort the request. Returning ``None`` is an
alternate way of indicating that the callback has consumed all of the
string passed to it and, hence, succeeded.
`header_test.py test`_ shows how to use ``WRITEFUNCTION``.
READFUNCTION
------------
.. function:: READFUNCTION(number of characters to read) -> byte string
Callback for reading data. Corresponds to `CURLOPT_READFUNCTION`_ in
libcurl.
On Python 3, the callback must return either a byte string or a Unicode
string consisting of ASCII code points only.
In addition, ``READFUNCTION`` may return ``READFUNC_ABORT`` or
``READFUNC_PAUSE``. See the libcurl documentation for an explanation
of these values.
The `file_upload.py example`_ in the distribution contains example code for
using ``READFUNCTION``.
.. _SEEKFUNCTION:
SEEKFUNCTION
------------
.. function:: SEEKFUNCTION(offset, origin) -> status
Callback for seek operations. Corresponds to `CURLOPT_SEEKFUNCTION`_
in libcurl.
IOCTLFUNCTION
-------------
.. function:: IOCTLFUNCTION(ioctl cmd) -> status
Callback for I/O operations. Corresponds to `CURLOPT_IOCTLFUNCTION`_
in libcurl.
*Note:* this callback is deprecated. Use :ref:`SEEKFUNCTION ` instead.
DEBUGFUNCTION
-------------
.. function:: DEBUGFUNCTION(debug message type, debug message byte string) -> None
Callback for debug information. Corresponds to `CURLOPT_DEBUGFUNCTION`_
in libcurl.
*Changed in version 7.19.5.2:* The second argument to a ``DEBUGFUNCTION``
callback is now of type ``bytes`` on Python 3. Previously the argument was
of type ``str``.
`debug_test.py test`_ shows how to use ``DEBUGFUNCTION``.
Example: Debug callbacks
~~~~~~~~~~~~~~~~~~~~~~~~
This example shows how to use the debug callback. The debug message type is
an integer indicating the type of debug message. The VERBOSE option must be
enabled for this callback to be invoked.
::
def test(debug_type, debug_msg):
print "debug(%d): %s" % (debug_type, debug_msg)
c = pycurl.Curl()
c.setopt(pycurl.URL, "https://curl.haxx.se/")
c.setopt(pycurl.VERBOSE, 1)
c.setopt(pycurl.DEBUGFUNCTION, test)
c.perform()
PROGRESSFUNCTION
----------------
.. function:: PROGRESSFUNCTION(download total, downloaded, upload total, uploaded) -> status
Callback for progress meter. Corresponds to `CURLOPT_PROGRESSFUNCTION`_
in libcurl.
``PROGRESSFUNCTION`` receives amounts as floating point arguments to the
callback. Since libcurl 7.32.0 ``PROGRESSFUNCTION`` is deprecated;
``XFERINFOFUNCTION`` should be used instead which receives amounts as
long integers.
``NOPROGRESS`` option must be set for False libcurl to invoke a
progress callback, as PycURL by default sets ``NOPROGRESS`` to True.
XFERINFOFUNCTION
----------------
.. function:: XFERINFOFUNCTION(download total, downloaded, upload total, uploaded) -> status
Callback for progress meter. Corresponds to `CURLOPT_XFERINFOFUNCTION`_
in libcurl.
``XFERINFOFUNCTION`` receives amounts as long integers.
``NOPROGRESS`` option must be set for False libcurl to invoke a
progress callback, as PycURL by default sets ``NOPROGRESS`` to True.
Example: Download/upload progress callback
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This example shows how to use the progress callback. When downloading a
document, the arguments related to uploads are zero, and vice versa.
::
## Callback function invoked when download/upload has progress
def progress(download_t, download_d, upload_t, upload_d):
print "Total to download", download_t
print "Total downloaded", download_d
print "Total to upload", upload_t
print "Total uploaded", upload_d
c = pycurl.Curl()
c.setopt(c.URL, "http://slashdot.org/")
c.setopt(c.NOPROGRESS, False)
c.setopt(c.XFERINFOFUNCTION, progress)
c.perform()
OPENSOCKETFUNCTION
------------------
.. function:: OPENSOCKETFUNCTION(purpose, address) -> int
Callback for opening sockets. Corresponds to
`CURLOPT_OPENSOCKETFUNCTION`_ in libcurl.
*purpose* is a ``SOCKTYPE_*`` value.
*address* is a `namedtuple`_ with ``family``, ``socktype``, ``protocol``
and ``addr`` fields, per `CURLOPT_OPENSOCKETFUNCTION`_ documentation.
*addr* is an object representing the address. Currently the following
address families are supported:
- ``AF_INET``: *addr* is a 2-tuple of ``(host, port)``.
- ``AF_INET6``: *addr* is a 4-tuple of ``(host, port, flow info, scope id)``.
- ``AF_UNIX``: *addr* is a byte string containing path to the Unix socket.
Availability: Unix.
This behavior matches that of Python's `socket module`_.
The callback should return a socket object, a socket file descriptor
or a Python object with a ``fileno`` property containing the socket
file descriptor.
The callback may be unset by calling :ref:`setopt ` with ``None``
as the value or by calling :ref:`unsetopt `.
`open_socket_cb_test.py test`_ shows how to use ``OPENSOCKETFUNCTION``.
*Changed in version 7.21.5:* Previously, the callback received ``family``,
``socktype``, ``protocol`` and ``addr`` parameters (``purpose`` was
not passed and ``address`` was flattened). Also, ``AF_INET6`` addresses
were exposed as 2-tuples of ``(host, port)`` rather than 4-tuples.
*Changed in version 7.19.3:* ``addr`` parameter added to the callback.
CLOSESOCKETFUNCTION
-------------------
.. function:: CLOSESOCKETFUNCTION(curlfd) -> int
Callback for setting socket options. Corresponds to
`CURLOPT_CLOSESOCKETFUNCTION`_ in libcurl.
*curlfd* is the file descriptor to be closed.
The callback should return an ``int``.
The callback may be unset by calling :ref:`setopt ` with ``None``
as the value or by calling :ref:`unsetopt `.
`close_socket_cb_test.py test`_ shows how to use ``CLOSESOCKETFUNCTION``.
SOCKOPTFUNCTION
---------------
.. function:: SOCKOPTFUNCTION(curlfd, purpose) -> int
Callback for setting socket options. Corresponds to `CURLOPT_SOCKOPTFUNCTION`_
in libcurl.
*curlfd* is the file descriptor of the newly created socket.
*purpose* is a ``SOCKTYPE_*`` value.
The callback should return an ``int``.
The callback may be unset by calling :ref:`setopt ` with ``None``
as the value or by calling :ref:`unsetopt `.
`sockopt_cb_test.py test`_ shows how to use ``SOCKOPTFUNCTION``.
SSH_KEYFUNCTION
---------------
.. function:: SSH_KEYFUNCTION(known_key, found_key, match) -> int
Callback for known host matching logic. Corresponds to
`CURLOPT_SSH_KEYFUNCTION`_ in libcurl.
*known_key* and *found_key* are instances of ``KhKey`` class which is a
`namedtuple`_ with ``key`` and ``keytype`` fields, corresponding to
libcurl's ``struct curl_khkey``::
KhKey = namedtuple('KhKey', ('key', 'keytype'))
On Python 2, the *key* field of ``KhKey`` is a ``str``. On Python 3, the
*key* field is ``bytes``. *keytype* is an ``int``.
*known_key* may be ``None`` when there is no known matching host key.
``SSH_KEYFUNCTION`` callback should return a ``KHSTAT_*`` value.
The callback may be unset by calling :ref:`setopt ` with ``None``
as the value or by calling :ref:`unsetopt `.
`ssh_key_cb_test.py test`_ shows how to use ``SSH_KEYFUNCTION``.
.. _CURLOPT_HEADERFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_HEADERFUNCTION.html
.. _CURLOPT_WRITEFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
.. _CURLOPT_READFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_READFUNCTION.html
.. _CURLOPT_PROGRESSFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
.. _CURLOPT_XFERINFOFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_XFERINFOFUNCTION.html
.. _CURLOPT_DEBUGFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_DEBUGFUNCTION.html
.. _CURLOPT_SEEKFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_SEEKFUNCTION.html
.. _CURLOPT_IOCTLFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_IOCTLFUNCTION.html
.. _file_upload.py example: https://github.com/pycurl/pycurl/blob/master/examples/file_upload.py
.. _write_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/write_test.py
.. _header_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/header_test.py
.. _debug_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/debug_test.py
.. _CURLOPT_SSH_KEYFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_SSH_KEYFUNCTION.html
.. _namedtuple: https://docs.python.org/library/collections.html#collections.namedtuple
.. _CURLOPT_SOCKOPTFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_SOCKOPTFUNCTION.html
.. _sockopt_cb_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/sockopt_cb_test.py
.. _ssh_key_cb_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/ssh_key_cb_test.py
.. _CURLOPT_CLOSESOCKETFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_CLOSESOCKETFUNCTION.html
.. _close_socket_cb_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/close_socket_cb_test.py
.. _CURLOPT_OPENSOCKETFUNCTION: https://curl.haxx.se/libcurl/c/CURLOPT_OPENSOCKETFUNCTION.html
.. _open_socket_cb_test.py test: https://github.com/pycurl/pycurl/blob/master/tests/open_socket_cb_test.py
.. _socket module: https://docs.python.org/library/socket.html
pycurl-7.43.0.2/doc/release-notes.rst 0000644 0001750 0001750 00000000042 13211045142 016341 0 ustar me me 0000000 0000000 .. include:: ../RELEASE-NOTES.rst
pycurl-7.43.0.2/doc/release-process.rst 0000644 0001750 0001750 00000002533 13304422026 016701 0 ustar me me 0000000 0000000 Release Process
===============
1. Ensure changelog is up to date with commits in master.
2. Run ``python setup.py authors`` and review the updated AUTHORS file.
3. Run ``git shortlog REL_...`` and add new contributors
missed by the authors script to AUTHORS.
4. Run ``python setup.py manifest``, check that none of the listed files
should be in MANIFEST.in.
5. Check ``get_data_files()`` in ``setup.py`` to see if any new files should
be included in binary distributions.
6. Make sure Travis and AppVeyor are green for master.
7. Update version numbers in:
- Changelog (also record release date)
- doc/conf.py
- setup.py
- winbuild.py
8. Update copyright years if necessary.
9. Draft release notes, add to RELEASE-NOTES.rst.
10. ``make gen docs``.
11. ``python setup.py sdist``.
12. Manually test install the built package.
13. Build windows packages using winbuild.py.
14. Add sdist and windows packages to downloads repo on github.
15. Tag the new version.
16. Register new version with pypi - ``python setup.py register``.
17. Upload source distribution to pypi using twine.
18. Upload windows wheels to pypi using twine.
19. Upload windows exe installers to pypi using twine.
20. Upload release files to bintray.
21. Push tag to github pycurl repo.
22. Announce release on mailing list.
23. Link to announcement from website.
pycurl-7.43.0.2/doc/quickstart.rst 0000644 0001750 0001750 00000033006 13277672061 016015 0 ustar me me 0000000 0000000 PycURL Quick Start
==================
Retrieving A Network Resource
-----------------------------
Once PycURL is installed we can perform network operations. The simplest
one is retrieving a resource by its URL. To issue a network request with
PycURL, the following steps are required:
1. Create a ``pycurl.Curl`` instance.
2. Use ``setopt`` to set options.
3. Call ``perform`` to perform the operation.
Here is how we can retrieve a network resource in Python 2::
import pycurl
from StringIO import StringIO
buffer = StringIO()
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/')
c.setopt(c.WRITEDATA, buffer)
c.perform()
c.close()
body = buffer.getvalue()
# Body is a string in some encoding.
# In Python 2, we can print it without knowing what the encoding is.
print(body)
This code is available as ``examples/quickstart/get_python2.py``.
PycURL does not provide storage for the network response - that is the
application's job. Therefore we must setup a buffer (in the form of a
StringIO object) and instruct PycURL to write to that buffer.
Most of the existing PycURL code uses WRITEFUNCTION instead of WRITEDATA
as follows::
c.setopt(c.WRITEFUNCTION, buffer.write)
While the WRITEFUNCTION idiom continues to work, it is now unnecessary.
As of PycURL 7.19.3 WRITEDATA accepts any Python object with a ``write``
method.
Python 3 version is slightly more complicated::
import pycurl
from io import BytesIO
buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/')
c.setopt(c.WRITEDATA, buffer)
c.perform()
c.close()
body = buffer.getvalue()
# Body is a byte string.
# We have to know the encoding in order to print it to a text file
# such as standard output.
print(body.decode('iso-8859-1'))
This code is available as ``examples/quickstart/get_python3.py``.
In Python 3, PycURL response the response body as a byte string.
This is handy if we are downloading a binary file, but for text documents
we must decode the byte string. In the above example, we assume that the
body is encoded in iso-8859-1.
Python 2 and Python 3 versions can be combined. Doing so requires decoding
the response body as in Python 3 version. The code for the combined
example can be found in ``examples/quickstart/get.py``.
Working With HTTPS
------------------
Most web sites today use HTTPS which is HTTP over TLS/SSL. In order to
take advantage of security that HTTPS provides, PycURL needs to utilize
a *certificate bundle*. As certificates change over time PycURL does not
provide such a bundle; one may be supplied by your operating system, but
if not, consider using the `certifi`_ Python package::
import pycurl
import certifi
from StringIO import StringIO
buffer = StringIO()
c = pycurl.Curl()
c.setopt(c.URL, 'https://python.org/')
c.setopt(c.WRITEDATA, buffer)
c.setopt(c.CAINFO, certifi.where())
c.perform()
c.close()
body = buffer.getvalue()
print(body)
This code is available as ``examples/quickstart/get_python2_https.py`` and
``examples/quickstart/get_python3_https.py``.
Troubleshooting
---------------
When things don't work as expected, use libcurl's ``VERBOSE`` option to
receive lots of debugging output pertaining to the request::
c.setopt(c.VERBOSE, True)
It is often helpful to compare verbose output from the program using PycURL
with that of ``curl`` command line tool when the latter is invoked with
``-v`` option::
curl -v http://pycurl.io/
Examining Response Headers
--------------------------
In reality we want to decode the response using the encoding specified by
the server rather than assuming an encoding. To do this we need to
examine the response headers::
import pycurl
import re
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
headers = {}
def header_function(header_line):
# HTTP standard specifies that headers are encoded in iso-8859-1.
# On Python 2, decoding step can be skipped.
# On Python 3, decoding step is required.
header_line = header_line.decode('iso-8859-1')
# Header lines include the first status line (HTTP/1.x ...).
# We are going to ignore all lines that don't have a colon in them.
# This will botch headers that are split on multiple lines...
if ':' not in header_line:
return
# Break the header line into header name and value.
name, value = header_line.split(':', 1)
# Remove whitespace that may be present.
# Header lines include the trailing newline, and there may be whitespace
# around the colon.
name = name.strip()
value = value.strip()
# Header names are case insensitive.
# Lowercase name here.
name = name.lower()
# Now we can actually record the header name and value.
# Note: this only works when headers are not duplicated, see below.
headers[name] = value
buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io')
c.setopt(c.WRITEFUNCTION, buffer.write)
# Set our header function.
c.setopt(c.HEADERFUNCTION, header_function)
c.perform()
c.close()
# Figure out what encoding was sent with the response, if any.
# Check against lowercased header name.
encoding = None
if 'content-type' in headers:
content_type = headers['content-type'].lower()
match = re.search('charset=(\S+)', content_type)
if match:
encoding = match.group(1)
print('Decoding using %s' % encoding)
if encoding is None:
# Default encoding for HTML is iso-8859-1.
# Other content types may have different default encoding,
# or in case of binary data, may have no encoding at all.
encoding = 'iso-8859-1'
print('Assuming encoding is %s' % encoding)
body = buffer.getvalue()
# Decode using the encoding we figured out.
print(body.decode(encoding))
This code is available as ``examples/quickstart/response_headers.py``.
That was a lot of code for something very straightforward. Unfortunately,
as libcurl refrains from allocating memory for response data, it is on our
application to perform this grunt work.
One caveat with the above code is that if there are multiple headers
for the same name, such as Set-Cookie, only the last header value will be
stored. To record all values in multi-valued headers as a list the following
code can be used instead of ``headers[name] = value`` line::
if name in headers:
if isinstance(headers[name], list):
headers[name].append(value)
else:
headers[name] = [headers[name], value]
else:
headers[name] = value
Writing To A File
-----------------
Suppose we want to save response body to a file. This is actually easy
for a change::
import pycurl
# As long as the file is opened in binary mode, both Python 2 and Python 3
# can write response body to it without decoding.
with open('out.html', 'wb') as f:
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/')
c.setopt(c.WRITEDATA, f)
c.perform()
c.close()
This code is available as ``examples/quickstart/write_file.py``.
The important part is opening the file in binary mode - then response body
can be written bytewise without decoding or encoding steps.
Following Redirects
-------------------
By default libcurl, and PycURL, do not follow redirects. Changing this
behavior involves using ``setopt`` like so::
import pycurl
c = pycurl.Curl()
# Redirects to https://www.python.org/.
c.setopt(c.URL, 'http://www.python.org/')
# Follow redirect.
c.setopt(c.FOLLOWLOCATION, True)
c.perform()
c.close()
This code is available as ``examples/quickstart/follow_redirect.py``.
As we did not set a write callback, the default libcurl and PycURL behavior
to write response body to standard output takes effect.
Setting Options
---------------
Following redirects is one option that libcurl provides. There are many more
such options, and they are documented on `curl_easy_setopt`_ page.
With very few exceptions, PycURL option names are derived from libcurl
option names by removing the ``CURLOPT_`` prefix. Thus, ``CURLOPT_URL``
becomes simply ``URL``.
.. _curl_easy_setopt: https://curl.haxx.se/libcurl/c/curl_easy_setopt.html
Examining Response
------------------
We already covered examining response headers. Other response information is
accessible via ``getinfo`` call as follows::
import pycurl
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
buffer = BytesIO()
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io/')
c.setopt(c.WRITEDATA, buffer)
c.perform()
# HTTP response code, e.g. 200.
print('Status: %d' % c.getinfo(c.RESPONSE_CODE))
# Elapsed time for the transfer.
print('Status: %f' % c.getinfo(c.TOTAL_TIME))
# getinfo must be called before close.
c.close()
This code is available as ``examples/quickstart/response_info.py``.
Here we write the body to a buffer to avoid printing uninteresting output
to standard out.
Response information that libcurl exposes is documented on
`curl_easy_getinfo`_ page. With very few exceptions, PycURL constants
are derived from libcurl constants by removing the ``CURLINFO_`` prefix.
Thus, ``CURLINFO_RESPONSE_CODE`` becomes simply ``RESPONSE_CODE``.
.. _curl_easy_getinfo: https://curl.haxx.se/libcurl/c/curl_easy_getinfo.html
Sending Form Data
-----------------
To send form data, use ``POSTFIELDS`` option. Form data must be URL-encoded
beforehand::
import pycurl
try:
# python 3
from urllib.parse import urlencode
except ImportError:
# python 2
from urllib import urlencode
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
post_data = {'field': 'value'}
# Form data must be provided already urlencoded.
postfields = urlencode(post_data)
# Sets request method to POST,
# Content-Type header to application/x-www-form-urlencoded
# and data to send in request body.
c.setopt(c.POSTFIELDS, postfields)
c.perform()
c.close()
This code is available as ``examples/quickstart/form_post.py``.
``POSTFIELDS`` automatically sets HTTP request method to POST. Other request
methods can be specified via ``CUSTOMREQUEST`` option::
c.setopt(c.CUSTOMREQUEST, 'PATCH')
File Upload - Multipart POST
----------------------------
To replicate the behavior of file upload in an HTML form (specifically,
a multipart form),
use ``HTTPPOST`` option. Such an upload is performed with a ``POST`` request.
See the next example for how to upload a file with a ``PUT`` request.
If the data to be uploaded is located in a physical file,
use ``FORM_FILE``::
import pycurl
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
c.setopt(c.HTTPPOST, [
('fileupload', (
# upload the contents of this file
c.FORM_FILE, __file__,
)),
])
c.perform()
c.close()
This code is available as ``examples/quickstart/file_upload_real.py``.
``libcurl`` provides a number of options to tweak file uploads and multipart
form submissions in general. These are documented on `curl_formadd page`_.
For example, to set a different filename and content type::
import pycurl
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
c.setopt(c.HTTPPOST, [
('fileupload', (
# upload the contents of this file
c.FORM_FILE, __file__,
# specify a different file name for the upload
c.FORM_FILENAME, 'helloworld.py',
# specify a different content type
c.FORM_CONTENTTYPE, 'application/x-python',
)),
])
c.perform()
c.close()
This code is available as ``examples/quickstart/file_upload_real_fancy.py``.
If the file data is in memory, use ``BUFFER``/``BUFFERPTR`` as follows::
import pycurl
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/post')
c.setopt(c.HTTPPOST, [
('fileupload', (
c.FORM_BUFFER, 'readme.txt',
c.FORM_BUFFERPTR, 'This is a fancy readme file',
)),
])
c.perform()
c.close()
This code is available as ``examples/quickstart/file_upload_buffer.py``.
File Upload - PUT
-----------------
A file can also be uploaded in request body, via a ``PUT`` request.
Here is how this can be arranged with a physical file::
import pycurl
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/put')
c.setopt(c.UPLOAD, 1)
file = open('body.json')
c.setopt(c.READDATA, file)
c.perform()
c.close()
# File must be kept open while Curl object is using it
file.close()
This code is available as ``examples/quickstart/put_file.py``.
And if the data is stored in a buffer::
import pycurl
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
c = pycurl.Curl()
c.setopt(c.URL, 'https://httpbin.org/put')
c.setopt(c.UPLOAD, 1)
data = '{"json":true}'
# READDATA requires an IO-like object; a string is not accepted
# encode() is necessary for Python 3
buffer = BytesIO(data.encode('utf-8'))
c.setopt(c.READDATA, buffer)
c.perform()
c.close()
This code is available as ``examples/quickstart/put_buffer.py``.
.. _curl_formadd page: https://curl.haxx.se/libcurl/c/curl_formadd.html
.. _certifi: https://pypi.org/project/certifi/
pycurl-7.43.0.2/doc/conf.py 0000644 0001750 0001750 00000013620 13304422026 014351 0 ustar me me 0000000 0000000 # -*- coding: utf-8 -*-
#
# PycURL documentation build configuration file, created by
# sphinx-quickstart on Tue Feb 4 03:14:18 2014.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys
import os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
]
# Add any paths that contain templates here, relative to this directory.
templates_path = ['templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8-sig'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'PycURL'
copyright = u'2001-2018 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.43.0.2'
# The full version, including alpha/beta/rc tags.
release = '7.43.0.2'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
exclude_patterns = ['docstrings']
# The reST default role (used for this markup: `text`) to use for all
# documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# If true, keep warnings as "system message" paragraphs in the built documents.
#keep_warnings = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# " v documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
html_favicon = 'favicon.ico'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['static']
# Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation.
#html_extra_path = []
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_domain_indices = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
#html_show_sphinx = True
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
#html_show_copyright = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# This is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = None
# Output file base name for HTML help builder.
htmlhelp_basename = 'PycURLdoc'
pycurl-7.43.0.2/doc/curlobject.rst 0000644 0001750 0001750 00000001471 13301332107 015736 0 ustar me me 0000000 0000000 .. _curlobject:
Curl Object
===========
.. autoclass:: pycurl.Curl
Curl objects have the following methods:
.. automethod:: pycurl.Curl.close
.. _setopt:
.. automethod:: pycurl.Curl.setopt
.. _perform:
.. automethod:: pycurl.Curl.perform
.. _perform_rb:
.. automethod:: pycurl.Curl.perform_rb
.. _perform_rs:
.. automethod:: pycurl.Curl.perform_rs
.. _getinfo:
.. automethod:: pycurl.Curl.getinfo
.. _getinfo_raw:
.. automethod:: pycurl.Curl.getinfo_raw
.. automethod:: pycurl.Curl.reset
.. _unsetopt:
.. automethod:: pycurl.Curl.unsetopt
.. automethod:: pycurl.Curl.pause
.. _errstr:
.. automethod:: pycurl.Curl.errstr
.. _errstr_raw:
.. automethod:: pycurl.Curl.errstr_raw
.. automethod:: pycurl.Curl.setopt_string
pycurl-7.43.0.2/doc/index.rst 0000644 0001750 0001750 00000011240 13300450603 014705 0 ustar me me 0000000 0000000 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/
About libcurl
-------------
- libcurl is a free and easy-to-use client-side URL transfer library, supporting
DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3,
POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, Telnet and TFTP.
libcurl supports SSL certificates, HTTP POST, HTTP PUT,
FTP uploading, HTTP form based upload, proxies, cookies, user+password
authentication (Basic, Digest, NTLM, Negotiate, Kerberos4), file transfer
resume, http proxy tunneling and more!
- libcurl is highly portable, it builds and works identically on numerous
platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX, IRIX,
AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOs, Mac OS X,
Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS and more...
- libcurl is `free`_, :ref:`thread-safe `, `IPv6 compatible`_, `feature rich`_,
`well supported`_, `fast`_, `thoroughly documented`_ and is already used by
many known, big and successful `companies`_ and numerous `applications`_.
.. _free: https://curl.haxx.se/docs/copyright.html
.. _thread-safe: :ref:`thread-safety`
.. _`IPv6 compatible`: https://curl.haxx.se/libcurl/features.html#ipv6
.. _`feature rich`: https://curl.haxx.se/libcurl/features.html#features
.. _`well supported`: https://curl.haxx.se/libcurl/features.html#support
.. _`fast`: https://curl.haxx.se/libcurl/features.html#fast
.. _`thoroughly documented`: https://curl.haxx.se/libcurl/features.html#docs
.. _companies: https://curl.haxx.se/docs/companies.html
.. _applications: https://curl.haxx.se/libcurl/using/apps.html
Requirements
------------
- Python 2.7 or 3.4 through 3.6.
- libcurl 7.19.0 or better.
Installation
------------
On Unix, PycURL is easiest to install using your operating system's package
manager. This will also install libcurl and other dependencies as needed.
Installation via easy_install and pip is also supported::
easy_install pycurl
pip install pycurl
If this does not work, please see :ref:`install`.
On Windows, use pip to install a binary wheel for Python 2.7, 3.5 or 3.6::
pip install pycurl
If not using pip, binary distributions in other formats are available
`on Bintray`_.
.. _on Bintray: https://dl.bintray.com/pycurl/pycurl/
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 PycURL users as well.
Bugs can be reported `via GitHub`_. Please only use GitHub issues when you are
certain you have found a bug in PycURL. If you do not have a patch to fix
the bug, or at least a specific code fragment in PycURL that you believe is
the cause, you should instead post your inquiry to the mailing list.
.. _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
Documentation Contents
----------------------
.. toctree::
:maxdepth: 2
release-notes
install
quickstart
troubleshooting
pycurl
curlobject
curlmultiobject
curlshareobject
callbacks
curl
unicode
files
thread-safety
unimplemented
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
.. _libcurl: https://curl.haxx.se/libcurl/
.. _urllib: http://docs.python.org/library/urllib.html
pycurl-7.43.0.2/doc/files.rst 0000644 0001750 0001750 00000003451 13211045147 014711 0 ustar me me 0000000 0000000 File Handling
=============
In PycURL 7.19.0.3 and below, ``CURLOPT_READDATA``, ``CURLOPT_WRITEDATA`` and
``CURLOPT_WRITEHEADER`` options accepted file objects and directly passed
the underlying C library ``FILE`` pointers to libcurl.
Python 3 no longer implements files as C library ``FILE`` objects.
In PycURL 7.19.3 and above, when running on Python 3, these options
are implemented as calls to ``CURLOPT_READFUNCTION``, ``CURLOPT_WRITEFUNCTION``
and ``CURLOPT_HEADERFUNCTION``, respectively, with the write method of the
Python file object as the parameter. As a result, any Python file-like
object implementing a ``read`` method can be passed to ``CURLOPT_READDATA``,
and any Python file-like object implementing a ``write`` method can be
passed to ``CURLOPT_WRITEDATA`` or ``CURLOPT_WRITEHEADER`` options.
When running PycURL 7.19.3 and above on Python 2, the old behavior of
passing ``FILE`` pointers to libcurl remains when a true file object is given
to ``CURLOPT_READDATA``, ``CURLOPT_WRITEDATA`` and ``CURLOPT_WRITEHEADER``
options. For consistency with Python 3 behavior these options also accept
file-like objects implementing a ``read`` or ``write`` method, as appropriate,
as arguments, in which case the Python 3 code path is used converting these
options to ``CURLOPT_*FUNCTION`` option calls.
Files given to PycURL as arguments to ``CURLOPT_READDATA``,
``CURLOPT_WRITEDATA`` or ``CURLOPT_WRITEHEADER`` must be opened for reading or
writing in binary mode. Files opened in text mode (without ``"b"`` flag to
``open()``) expect string objects and reading from or writing to them from
PycURL will fail. Similarly when passing ``f.write`` method of an open file to
``CURLOPT_WRITEFUNCTION`` or ``CURLOPT_HEADERFUNCTION``, or ``f.read`` to
``CURLOPT_READFUNCTION``, the file must have been be opened in binary mode.
pycurl-7.43.0.2/doc/install.rst 0000644 0001750 0001750 00000000034 13211045142 015242 0 ustar me me 0000000 0000000 .. include:: ../INSTALL.rst
pycurl-7.43.0.2/doc/internals.rst 0000644 0001750 0001750 00000000504 13151540633 015605 0 ustar me me 0000000 0000000 Internals
=========
Cleanup sequence:
x=curl/multi/share
x.close() -> do_x_close -> util_x_close
del x -> do_x_dealloc -> util_x_close
do_* functions are directly invoked by user code.
They check pycurl object state.
util_* functions are only invoked by other pycurl C functions.
They do not check pycurl object state.
pycurl-7.43.0.2/doc/curlmultiobject.rst 0000644 0001750 0001750 00000001140 13211045147 017007 0 ustar me me 0000000 0000000 .. _curlmultiobject:
CurlMulti Object
================
.. autoclass:: pycurl.CurlMulti
CurlMulti objects have the following methods:
.. automethod:: pycurl.CurlMulti.close
.. automethod:: pycurl.CurlMulti.add_handle
.. automethod:: pycurl.CurlMulti.remove_handle
.. automethod:: pycurl.CurlMulti.perform
.. automethod:: pycurl.CurlMulti.setopt
.. automethod:: pycurl.CurlMulti.fdset
.. automethod:: pycurl.CurlMulti.select
.. automethod:: pycurl.CurlMulti.info_read
.. automethod:: pycurl.CurlMulti.timeout
.. automethod:: pycurl.CurlMulti.assign
pycurl-7.43.0.2/doc/troubleshooting.rst 0000644 0001750 0001750 00000012043 13244604237 017042 0 ustar me me 0000000 0000000 Troubleshooting
===============
The first step of troubleshooting issues in programs using PycURL is
identifying which piece of software is responsible for the misbehavior.
PycURL is a thin wrapper around libcurl; libcurl performs most of the
network operations and transfer-related issues are generally the domain
of libcurl.
``setopt``-Related Issues
-------------------------
:ref:`setopt ` is one method that is used for setting most
of the libcurl options, as such calls to it can fail in a wide variety
of ways.
``TypeError: invalid arguments to setopt``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This usually means the *type* of argument passed to ``setopt`` does not
match what the option expects. Recent versions of PycURL have improved
error reporting when this happens and they also accept more data types
(for example tuples in addition to lists). If you are using an old version of
PycURL, upgrading to the last version may help troubleshoot the situation.
The next step is carefully reading libcurl documentation for the option
in question and verifying that the type, structure and format of data
you are passing matches what the option expects.
``pycurl.error: (1, '')``
~~~~~~~~~~~~~~~~~~~~~~~~~
An exception like this means PycURL accepted the structure and values
in the option parameter and sent them on to libcurl, and
libcurl rejected the attempt to set the option.
Until PycURL implements an error code to symbol mapping,
you have to perform this mapping by hand. Error codes are
found in the file `curl.h`_ in libcurl source; look for ``CURLE_OK``.
For example, error code 1 means ``CURLE_UNSUPPORTED_PROTOCOL``.
libcurl can reject a ``setopt`` call for a variety of reasons of its own,
including but not limited to the requested functionality
`not being compiled in`_ or being not supported with the SSL backend
being used.
Transfer-Related Issues
-----------------------
If your issue is transfer-related (timeout, connection failure, transfer
failure, ``perform`` hangs, etc.) the first step in troubleshooting is
setting the ``VERBOSE`` flag for the operation. libcurl will then output
debugging information as the transfer executes::
>>> import pycurl
>>> curl = pycurl.Curl()
>>> curl.setopt(curl.VERBOSE, True)
>>> curl.setopt(curl.URL, 'https://www.python.org')
>>> curl.setopt(curl.WRITEDATA, open('/dev/null', 'w'))
>>> curl.perform()
* Hostname www.python.org was found in DNS cache
* Trying 151.101.208.223...
* TCP_NODELAY set
* Connected to www.python.org (151.101.208.223) port 443 (#1)
* found 173 certificates in /etc/ssl/certs/ca-certificates.crt
* found 696 certificates in /etc/ssl/certs
* ALPN, offering http/1.1
* SSL re-using session ID
* SSL connection using TLS1.2 / ECDHE_RSA_AES_128_GCM_SHA256
* server certificate verification OK
* server certificate status verification SKIPPED
* common name: www.python.org (matched)
* server certificate expiration date OK
* server certificate activation date OK
* certificate public key: RSA
* certificate version: #3
* subject:
* start date: Sat, 17 Jun 2017 00:00:00 GMT
* expire date: Thu, 27 Sep 2018 12:00:00 GMT
* issuer: C=US,O=DigiCert Inc,OU=www.digicert.com,CN=DigiCert SHA2 Extended Validation Server CA
* compression: NULL
* ALPN, server accepted to use http/1.1
> GET / HTTP/1.1
Host: www.python.org
User-Agent: PycURL/7.43.0.1 libcurl/7.52.1 GnuTLS/3.5.8 zlib/1.2.8 libidn2/0.16 libpsl/0.17.0 (+libidn2/0.16) libssh2/1.7.0 nghttp2/1.18.1 librtmp/2.3
Accept: */*
< HTTP/1.1 200 OK
< Server: nginx
< Content-Type: text/html; charset=utf-8
< X-Frame-Options: SAMEORIGIN
< x-xss-protection: 1; mode=block
< X-Clacks-Overhead: GNU Terry Pratchett
< Via: 1.1 varnish
< Fastly-Debug-Digest: a63ab819df3b185a89db37a59e39f0dd85cf8ee71f54bbb42fae41670ae56fd2
< Content-Length: 48893
< Accept-Ranges: bytes
< Date: Thu, 07 Dec 2017 07:28:32 GMT
< Via: 1.1 varnish
< Age: 2497
< Connection: keep-alive
< X-Served-By: cache-iad2146-IAD, cache-ewr18146-EWR
< X-Cache: HIT, HIT
< X-Cache-Hits: 2, 2
< X-Timer: S1512631712.274059,VS0,VE0
< Vary: Cookie
< Strict-Transport-Security: max-age=63072000; includeSubDomains
<
* Curl_http_done: called premature == 0
* Connection #1 to host www.python.org left intact
>>>
The verbose output in the above example includes:
- DNS resolution
- SSL connection
- SSL certificate verification
- Headers sent to the server
- Headers received from the server
If the verbose output indicates something you believe is incorrect,
the next step is to perform an identical transfer using ``curl`` command-line
utility and verify that the behavior is PycURL-specific, as in most cases
it is not. This is also a good time to check the behavior of the latest
version of libcurl.
.. _curl.h: https://github.com/curl/curl/blob/master/include/curl/curl.h#L456
.. _not being compiled in: https://github.com/pycurl/pycurl/issues/477
pycurl-7.43.0.2/doc/pycurl.rst 0000644 0001750 0001750 00000001240 13211045165 015117 0 ustar me me 0000000 0000000 pycurl Module Functionality
===========================
.. module:: pycurl
.. autofunction:: pycurl.global_init
.. autofunction:: pycurl.global_cleanup
.. data:: version
This is a string with version information on libcurl, corresponding to
`curl_version`_ in libcurl.
Example usage:
::
>>> import pycurl
>>> pycurl.version
'PycURL/7.19.3 libcurl/7.33.0 OpenSSL/0.9.8x zlib/1.2.7'
.. autofunction:: pycurl.version_info
.. autoclass:: pycurl.Curl
:noindex:
.. autoclass:: pycurl.CurlMulti
:noindex:
.. autoclass:: pycurl.CurlShare
:noindex:
.. _curl_version: https://curl.haxx.se/libcurl/c/curl_version.html
pycurl-7.43.0.2/MANIFEST.in 0000644 0001750 0001750 00000002277 13301173520 014050 0 ustar me me 0000000 0000000 #
# MANIFEST.in
# Manifest template for creating the source distribution.
#
include AUTHORS
include COPYING-LGPL
include COPYING-MIT
include ChangeLog
include INSTALL.rst
include MANIFEST.in
include Makefile
include README.rst
include RELEASE-NOTES.rst
include doc/*.py
include doc/*.rst
include doc/docstrings/*.rst
include doc/static/favicon.ico
include examples/*.py
include examples/quickstart/*.py
include examples/tests/*.py
include src/Makefile
include src/docstrings.c
include src/docstrings.h
include src/easy.c
include src/easycb.c
include src/easyinfo.c
include src/easyopt.c
include src/easyperform.c
include src/module.c
include src/multi.c
include src/oscompat.c
include src/pycurl.h
include src/pythoncompat.c
include src/share.c
include src/stringcompat.c
include src/threadsupport.c
include src/util.c
include python/curl/*.py
include requirements*.txt
include tests/*.py
include tests/certs/*.crt
include tests/certs/*.key
include tests/ext/*.sh
include tests/fake-curl/*
include tests/fake-curl/libcurl/*
include tests/fixtures/form_submission.txt
include tests/matrix/*.patch
include tests/run.sh
include tests/run-quickstart.sh
include tests/vsftpd.conf
include winbuild.py
include winbuild/*
pycurl-7.43.0.2/Makefile 0000644 0001750 0001750 00000013446 13301173520 013752 0 ustar me me 0000000 0000000 #
# to use a specific python version call
# `make PYTHON=python2.7'
#
SHELL = /bin/sh
PYTHON = python
NOSETESTS = nosetests
PYFLAKES = pyflakes
# -c on linux
# freebsd does not understand -c
CHMOD_VERBOSE=-v
BUILD_WWW = build/www
RSYNC = rsync
##RSYNC_FLAGS = -av --relative -e ssh
RSYNC_FLAGS = -av --relative --delete --delete-after -e ssh
RSYNC_FILES = \
htdocs \
htdocs/download/.htaccess \
upload
RSYNC_EXCLUDES = \
'--exclude=htdocs/download/' \
'--exclude=upload/Ignore/' \
'--exclude=htdocs/travis-deps/'
RSYNC_TARGET = /home/groups/p/py/pycurl/
RSYNC_USER = armco@web.sourceforge.net
# src/module.c is first because it declares global variables
# which other files reference; important for single source build
SOURCES = src/easy.c src/easycb.c src/easyinfo.c src/easyopt.c src/easyperform.c \
src/module.c src/multi.c src/oscompat.c src/pythoncompat.c \
src/share.c src/stringcompat.c src/threadsupport.c src/util.c
GEN_SOURCES = src/docstrings.c src/docstrings.h
ALL_SOURCES = src/pycurl.h $(GEN_SOURCES) $(SOURCES)
RELEASE_SOURCES = src/allpycurl.c
DOCSTRINGS_SOURCES = \
doc/docstrings/curl.rst \
doc/docstrings/curl_close.rst \
doc/docstrings/curl_errstr.rst \
doc/docstrings/curl_errstr_raw.rst \
doc/docstrings/curl_getinfo.rst \
doc/docstrings/curl_getinfo_raw.rst \
doc/docstrings/curl_pause.rst \
doc/docstrings/curl_perform.rst \
doc/docstrings/curl_reset.rst \
doc/docstrings/curl_setopt.rst \
doc/docstrings/curl_unsetopt.rst \
doc/docstrings/curl_set_ca_certs.rst \
doc/docstrings/multi.rst \
doc/docstrings/multi_add_handle.rst \
doc/docstrings/multi_assign.rst \
doc/docstrings/multi_close.rst \
doc/docstrings/multi_fdset.rst \
doc/docstrings/multi_info_read.rst \
doc/docstrings/multi_perform.rst \
doc/docstrings/multi_remove_handle.rst \
doc/docstrings/multi_select.rst \
doc/docstrings/multi_setopt.rst \
doc/docstrings/multi_socket_action.rst \
doc/docstrings/multi_socket_all.rst \
doc/docstrings/multi_timeout.rst \
doc/docstrings/pycurl_global_cleanup.rst \
doc/docstrings/pycurl_global_init.rst \
doc/docstrings/pycurl_module.rst \
doc/docstrings/pycurl_version_info.rst \
doc/docstrings/share.rst \
doc/docstrings/share_close.rst \
doc/docstrings/share_setopt.rst
all: build
src-release: $(RELEASE_SOURCES)
src/docstrings.c src/docstrings.h: $(DOCSTRINGS_SOURCES)
$(PYTHON) setup.py docstrings
src/allpycurl.c: $(ALL_SOURCES)
echo '#define PYCURL_SINGLE_FILE' >src/.tmp.allpycurl.c
cat src/pycurl.h >>src/.tmp.allpycurl.c
cat src/docstrings.c $(SOURCES) |sed -e 's/#include "pycurl.h"//' -e 's/#include "docstrings.h"//' >>src/.tmp.allpycurl.c
mv src/.tmp.allpycurl.c src/allpycurl.c
gen: $(ALL_SOURCES)
build: $(ALL_SOURCES)
$(PYTHON) setup.py build
build-release: $(RELEASE_SOURCES)
PYCURL_RELEASE=1 $(PYTHON) setup.py build
do-test:
cd tests/fake-curl/libcurl && make
./tests/run.sh
./tests/ext/test-suite.sh
$(PYFLAKES) python examples tests setup.py winbuild.py
test: build do-test
test-release: build-release do-test
# rails-style alias
c: console
console:
PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \
PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \
$(PYTHON)
# (needs GNU binutils)
strip: build
strip -p --strip-unneeded build/lib*/*.so
chmod -x build/lib*/*.so
install install_lib:
$(PYTHON) setup.py $@
clean:
-rm -rf build dist
-rm -f *.pyc *.pyo */*.pyc */*.pyo */*/*.pyc */*/*.pyo
-rm -f MANIFEST
-rm -f src/allpycurl.c $(GEN_SOURCES)
distclean: clean
maintainer-clean: distclean
dist sdist: distclean
$(PYTHON) setup.py sdist
run-quickstart:
./tests/run-quickstart.sh
# Rebuild missing or changed documentation.
# Editing docstrings in Python or C source will not cause the documentation
# to be rebuilt with this target, use docs-force instead.
docs: build
mkdir -p build/docstrings
for file in doc/docstrings/*.rst; do tail -n +3 $$file >build/docstrings/`basename $$file`; done
PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \
PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \
sphinx-build doc build/doc
cp ChangeLog build/doc
# Rebuild all documentation.
# As sphinx extracts documentation from pycurl modules, docs targets
# depend on build target.
docs-force: build
# sphinx-docs has an -a option but it does not seem to always
# rebuild everything
rm -rf build/doc
PYTHONSUFFIX=$$(python -V 2>&1 |awk '{print $$2}' |awk -F. '{print $$1 "." $$2}') && \
PYTHONPATH=$$(ls -d build/lib.*$$PYTHONSUFFIX):$$PYTHONPATH \
sphinx-build doc build/doc
cp ChangeLog build/doc
www: docs
mkdir -p build
rsync -a www build --delete
rsync -a build/doc/ build/www/htdocs/doc --exclude .buildinfo --exclude .doctrees
cp doc/static/favicon.ico build/www/htdocs
cp ChangeLog build/www/htdocs
rsync: rsync-prepare
cd $(BUILD_WWW) && \
$(RSYNC) $(RSYNC_FLAGS) $(RSYNC_EXCLUDES) $(RSYNC_FILES) $(RSYNC_USER):$(RSYNC_TARGET)
rsync-dry:
$(MAKE) rsync 'RSYNC=rsync --dry-run'
rsync-check:
$(MAKE) rsync 'RSYNC=rsync --dry-run -c'
# NOTE: Git does not maintain metadata like owners and file permissions,
# so we have to care manually.
# NOTE: rsync targets depend on www.
rsync-prepare:
chgrp $(CHMOD_VERBOSE) -R pycurl $(BUILD_WWW)
chmod $(CHMOD_VERBOSE) g+r `find $(BUILD_WWW) -perm +400 -print`
chmod $(CHMOD_VERBOSE) g+w `find $(BUILD_WWW) -perm +200 -print`
chmod $(CHMOD_VERBOSE) g+s `find $(BUILD_WWW) -type d -print`
## chmod $(CHMOD_VERBOSE) g+rws `find $(BUILD_WWW) -type d -perm -770 -print`
chmod $(CHMOD_VERBOSE) g+rws `find $(BUILD_WWW) -type d -print`
chmod $(CHMOD_VERBOSE) o-rwx $(BUILD_WWW)/upload
#-rm -rf `find $(BUILD_WWW) -name .xvpics -type d -print`
.PHONY: all build test do-test strip install install_lib \
clean distclean maintainer-clean dist sdist \
docs docs-force \
rsync rsync-dry rsync-check rsync-prepare
.NOEXPORT:
pycurl-7.43.0.2/winbuild.py 0000644 0001750 0001750 00000144536 13304422026 014507 0 ustar me me 0000000 0000000 # Bootstrap python binary:
# http://www.python.org/ftp/python/3.3.5/python-3.3.5.msi
# Then execute:
# msiexec /i c:\dev\build-pycurl\archives\python-3.3.5.msi /norestart /passive InstallAllUsers=1 Include_test=0 Include_doc=0 Include_launcher=0 Include_ckltk=0 TargetDir=c:\dev\32\python33
# msvc9/vs2008 express:
# http://go.microsoft.com/?linkid=7729279
# msvc10/vs2010 express:
# http://go.microsoft.com/?linkid=9709949
# for 64 bit builds, then install 2010 sp1:
# http://go.microsoft.com/fwlink/?LinkId=210710
# ... and windows 7 sdk (because sp1 compiler update refuses to install
# without it):
# http://www.microsoft.com/en-us/download/details.aspx?id=8279
# or http://www.microsoft.com/en-us/download/details.aspx?id=8442
# then install sp1 compiler update:
# https://www.microsoft.com/en-us/download/details.aspx?id=4422
# msvc14/vs2015 community:
# https://www.visualstudio.com/en-us/downloads/download-visual-studio-vs.aspx
#
# OpenSSL build resources including 64-bit builds:
# http://stackoverflow.com/questions/158232/how-do-you-compile-openssl-for-x64
# https://wiki.openssl.org/index.php/Compilation_and_Installation
# http://developer.covenanteyes.com/building-openssl-for-visual-studio/
#
# NASM:
# http://www.nasm.us/
# ActiveState Perl:
# http://www.activestate.com/activeperl/downloads
class Config:
'''User-adjustable configuration.
This class contains version numbers for dependencies,
which dependencies to use,
and where various binaries, headers and libraries are located in the filesystem.
'''
# work directory for downloading dependencies and building everything
root = 'c:/dev/build-pycurl'
# where msysgit is installed
git_root = 'c:/program files/git'
msysgit_bin_paths = [
"c:\\Program Files\\Git\\bin",
"c:\\Program Files\\Git\\usr\\bin",
#"c:\\Program Files\\Git\\mingw64\\bin",
]
# where NASM is installed, for building OpenSSL
nasm_path = ('c:/dev/nasm', 'c:/program files/nasm', 'c:/program files (x86)/nasm')
cmake_path = r"c:\Program Files\CMake\bin\cmake.exe"
gmake_path = r"c:\Program Files (x86)\GnuWin32\bin\make.exe"
# where ActiveState Perl is installed, for building 64-bit OpenSSL
activestate_perl_path = ('c:/perl64', r'c:\dev\perl64')
# which versions of python to build against
#python_versions = ['2.7.10', '3.2.5', '3.3.5', '3.4.3', '3.5.4', '3.6.2']
# these require only vc9 and vc14
python_versions = ['2.7.10', '3.5.4', '3.6.2']
# where pythons are installed
python_path_template = 'c:/dev/%(bitness)s/python%(python_release)s/python'
# overrides only, defaults are given in default_vc_paths below
vc_paths = {
# where msvc 9/vs 2008 is installed, for python 2.6 through 3.2
'vc9': None,
# where msvc 10/vs 2010 is installed, for python 3.3 through 3.4
'vc10': None,
# where msvc 14/vs 2015 is installed, for python 3.5 through 3.6
'vc14': None,
}
# whether to link libcurl against zlib
use_zlib = True
# which version of zlib to use, will be downloaded from internet
zlib_version = '1.2.11'
# whether to use openssl instead of winssl
use_openssl = True
# which version of openssl to use, will be downloaded from internet
openssl_version = '1.1.0h'
# whether to use c-ares
use_cares = True
cares_version = '1.14.0'
# whether to use libssh2
use_libssh2 = True
libssh2_version = '1.8.0'
use_nghttp2 = True
nghttp2_version = '1.32.0'
use_libidn = False
libiconv_version = '1.15'
libidn_version = '1.35'
# which version of libcurl to use, will be downloaded from internet
libcurl_version = '7.60.0'
# virtualenv version
virtualenv_version = '15.1.0'
# whether to build binary wheels
build_wheels = True
# pycurl version to build, we should know this ourselves
pycurl_version = '7.43.0.2'
# sometimes vc14 does not include windows sdk path in vcvars which breaks stuff.
# another application for this is to supply normaliz.lib for vc9
# which has an older version that doesn't have the symbols we need
windows_sdk_path = 'c:\\program files (x86)\\microsoft sdks\\windows\\v7.1a'
# ***
# No user-serviceable parts beyond this point
# ***
import os, os.path, sys, subprocess, shutil, contextlib, zipfile, re
try:
from urllib.request import urlopen
except ImportError:
from urllib import urlopen
# https://stackoverflow.com/questions/35569042/python-3-ssl-certificate-verify-failed
import ssl
try:
ssl._create_default_https_context = ssl._create_unverified_context
except AttributeError:
pass
def short_python_versions(python_versions):
return ['.'.join(python_version.split('.')[:2])
for python_version in python_versions]
def needed_vc_versions(python_versions):
return [vc_version for vc_version in config.vc_paths.keys()
if vc_version in [
PYTHON_VC_VERSIONS[short_python_version]
for short_python_version in short_python_versions(python_versions)]]
def select_existing_path(paths):
if isinstance(paths, list) or isinstance(paths, tuple):
for path in paths:
if os.path.exists(path):
return path
return paths[0]
else:
return paths
# This must be at top level as __file__ can be a relative path
# and changing current directory will break it
DIR_HERE = os.path.abspath(os.path.dirname(__file__))
def find_in_paths(binary, paths):
for path in paths:
if os.path.exists(os.path.join(path, binary)) or os.path.exists(os.path.join(path, binary + '.exe')):
return os.path.join(path, binary)
raise Exception('Could not find %s' % binary)
def check_call(cmd):
try:
subprocess.check_call(cmd)
except Exception as e:
raise Exception('Failed to execute ' + str(cmd) + ': ' + str(type(e)) + ': ' +str(e))
class ExtendedConfig(Config):
'''Global configuration that specifies what the entire process will do.
Unlike Config, this class contains also various derived properties
for convenience.
'''
def __init__(self, **kwargs):
for k in kwargs:
setattr(self, k, kwargs[k])
# These are defaults, overrides can be specified as vc_paths in Config above
default_vc_paths = {
# where msvc 9 is installed, for python 2.6-3.2
'vc9': [
'c:/program files (x86)/microsoft visual studio 9.0',
'c:/program files/microsoft visual studio 9.0',
],
# where msvc 10 is installed, for python 3.3-3.4
'vc10': [
'c:/program files (x86)/microsoft visual studio 10.0',
'c:/program files/microsoft visual studio 10.0',
],
# where msvc 14 is installed, for python 3.5-3.6
'vc14': [
'c:/program files (x86)/microsoft visual studio 14.0',
'c:/program files/microsoft visual studio 14.0',
],
}
@property
def nasm_path(self):
return select_existing_path(Config.nasm_path)
@property
def activestate_perl_path(self):
return select_existing_path(Config.activestate_perl_path)
@property
def archives_path(self):
return os.path.join(self.root, 'archives')
@property
def state_path(self):
return os.path.join(self.root, 'state')
@property
def git_bin_path(self):
#git_bin_path = os.path.join(git_root, 'bin')
return ''
@property
def git_path(self):
return os.path.join(self.git_bin_path, 'git')
@property
def rm_path(self):
return find_in_paths('rm', self.msysgit_bin_paths)
@property
def cp_path(self):
return find_in_paths('cp', self.msysgit_bin_paths)
@property
def sed_path(self):
return find_in_paths('sed', self.msysgit_bin_paths)
@property
def tar_path(self):
return find_in_paths('tar', self.msysgit_bin_paths)
@property
def activestate_perl_bin_path(self):
return os.path.join(self.activestate_perl_path, 'bin')
@property
def winbuild_patch_root(self):
return os.path.join(DIR_HERE, 'winbuild')
@property
def openssl_version_tuple(self):
return tuple(
int(part) if part < 'a' else part
for part in re.sub(r'([a-z])', r'.\1', self.openssl_version).split('.')
)
@property
def libssh2_version_tuple(self):
return tuple(int(part) for part in self.libssh2_version.split('.'))
@property
def cares_version_tuple(self):
return tuple(int(part) for part in self.cares_version.split('.'))
@property
def libcurl_version_tuple(self):
return tuple(int(part) for part in self.libcurl_version.split('.'))
@property
def python_releases(self):
return [PythonRelease('.'.join(version.split('.')[:2]))
for version in self.python_versions]
def buildconfigs(self):
return [BuildConfig(bitness=bitness, vc_version=vc_version)
for bitness in self.bitnesses
for vc_version in needed_vc_versions(self.python_versions)
]
BITNESSES = (32, 64)
PYTHON_VC_VERSIONS = {
'2.6': 'vc9',
'2.7': 'vc9',
'3.2': 'vc9',
'3.3': 'vc10',
'3.4': 'vc10',
'3.5': 'vc14',
'3.6': 'vc14',
}
def mkdir_p(path):
if not os.path.exists(path):
os.makedirs(path)
def rm_rf(path):
check_call([config.rm_path, '-rf', path])
def cp_r(src, dest):
check_call([config.cp_path, '-r', src, dest])
def fetch(url, archive=None):
if archive is None:
archive = os.path.basename(url)
if not os.path.exists(archive):
sys.stdout.write("Fetching %s\n" % url)
sys.stdout.flush()
io = urlopen(url)
tmp_path = os.path.join(os.path.dirname(archive),
'.%s.part' % os.path.basename(archive))
with open(tmp_path, 'wb') as f:
while True:
chunk = io.read(65536)
if len(chunk) == 0:
break
f.write(chunk)
os.rename(tmp_path, archive)
def fetch_to_archives(url):
mkdir_p(config.archives_path)
path = os.path.join(config.archives_path, os.path.basename(url))
fetch(url, path)
@contextlib.contextmanager
def in_dir(dir):
old_cwd = os.getcwd()
try:
os.chdir(dir)
yield
finally:
os.chdir(old_cwd)
@contextlib.contextmanager
def step(step_fn, args, target_dir):
#step = step_fn.__name__
state_tag = target_dir
mkdir_p(config.state_path)
state_file_path = os.path.join(config.state_path, state_tag)
if not os.path.exists(state_file_path) or not os.path.exists(target_dir):
step_fn(*args)
with open(state_file_path, 'w'):
pass
def untar(basename):
if os.path.exists(basename):
shutil.rmtree(basename)
check_call([config.tar_path, 'xf', '%s.tar.gz' % basename])
def require_file_exists(path):
if not os.path.exists(path):
raise Exception('Path %s does not exist!' % path)
return path
class PythonRelease(str):
@property
def dotless(self):
return self.replace('.', '')
class PythonVersion(str):
@property
def release(self):
return PythonRelease('.'.join(self.split('.')[:2]))
class PythonBinary(object):
def __init__(self, python_release, bitness):
self.python_release = python_release
self.bitness = bitness
@property
def executable_path(self):
return config.python_path_template % dict(
python_release=self.python_release.dotless,
bitness=self.bitness)
class Batch(object):
def __init__(self, bconf):
self.bconf = bconf
self.commands = []
self.add(self.vcvars_cmd)
self.add('echo on')
if self.bconf.vc_version == 'vc14':
# I don't know why vcvars doesn't configure this under vc14
self.add('set include=%s\\include;%%include%%' % self.bconf.windows_sdk_path)
if self.bconf.bitness == 32:
self.add('set lib=%s\\lib;%%lib%%' % self.bconf.windows_sdk_path)
self.add('set path=%s\\bin;%%path%%' % self.bconf.windows_sdk_path)
else:
self.add('set lib=%s\\lib\\x64;%%lib%%' % self.bconf.windows_sdk_path)
self.add('set path=%s\\bin\\x64;%%path%%' % self.bconf.windows_sdk_path)
self.add(self.nasm_cmd)
def add(self, cmd):
self.commands.append(cmd)
# if patch fails to apply hunks, it exits with nonzero code.
# if patch doesn't find the patch file to apply, it exits with a zero code!
ERROR_CHECK = 'IF %ERRORLEVEL% NEQ 0 exit %errorlevel%'
def batch_text(self):
return ("\n" + self.ERROR_CHECK + "\n").join(self.commands)
@property
def vcvars_bitness_parameter(self):
params = {
32: 'x86',
64: 'amd64',
}
return params[self.bconf.bitness]
@property
def vcvars_relative_path(self):
return 'vc/vcvarsall.bat'
@property
def vc_path(self):
if self.bconf.vc_version in config.vc_paths and config.vc_paths[self.bconf.vc_version]:
path = config.vc_paths[self.bconf.vc_version]
if not os.path.join(path, self.vcvars_relative_path):
raise Exception('vcvars not found in specified path')
return path
else:
for path in config.default_vc_paths[self.bconf.vc_version]:
if os.path.exists(os.path.join(path, self.vcvars_relative_path)):
return path
raise Exception('No usable vc path found')
@property
def vcvars_path(self):
return os.path.join(self.vc_path, self.vcvars_relative_path)
@property
def vcvars_cmd(self):
# https://msdn.microsoft.com/en-us/library/x4d2c09s.aspx
return "call \"%s\" %s" % (
self.vcvars_path,
self.vcvars_bitness_parameter,
)
@property
def nasm_cmd(self):
return "set path=%s;%%path%%\n" % config.nasm_path
class BuildConfig(ExtendedConfig):
'''Parameters for a particular build configuration.
Unlike ExtendedConfig, this class fixes bitness and Python version.
'''
def __init__(self, **kwargs):
ExtendedConfig.__init__(self, **kwargs)
for k in kwargs:
setattr(self, k, kwargs[k])
assert self.bitness
assert self.bitness in (32, 64)
assert self.vc_version
@property
def vc_tag(self):
return '%s-%s' % (self.vc_version, self.bitness)
class Builder(object):
def __init__(self, **kwargs):
self.bconf = kwargs.pop('bconf')
self.use_dlls = False
@contextlib.contextmanager
def execute_batch(self):
batch = Batch(self.bconf)
yield batch
with open('doit.bat', 'w') as f:
f.write(batch.batch_text())
if False:
print("Executing:")
with open('doit.bat', 'r') as f:
print(f.read())
sys.stdout.flush()
rv = subprocess.call(['doit.bat'])
if rv != 0:
print("\nFailed to execute the following commands:\n")
with open('doit.bat', 'r') as f:
print(f.read())
sys.stdout.flush()
exit(3)
class StandardBuilder(Builder):
@property
def state_tag(self):
return self.output_dir_path
@property
def bin_path(self):
return os.path.join(config.archives_path, self.output_dir_path, 'dist', 'bin')
@property
def include_path(self):
return os.path.join(config.archives_path, self.output_dir_path, 'dist', 'include')
@property
def lib_path(self):
return os.path.join(config.archives_path, self.output_dir_path, 'dist', 'lib')
@property
def dll_paths(self):
raise NotImplementedError
@property
def builder_name(self):
return self.__class__.__name__.replace('Builder', '').lower()
@property
def my_version(self):
return getattr(self.bconf, '%s_version' % self.builder_name)
@property
def output_dir_path(self):
return '%s-%s-%s' % (self.builder_name, self.my_version, self.bconf.vc_tag)
def standard_fetch_extract(self, url_template):
url = url_template % dict(
my_version=self.my_version,
)
fetch(url)
archive_basename = os.path.basename(url)
archive_name = archive_basename.replace('.tar.gz', '')
untar(archive_name)
suffixed_dir = self.output_dir_path
if os.path.exists(suffixed_dir):
shutil.rmtree(suffixed_dir)
os.rename(archive_name, suffixed_dir)
return suffixed_dir
class ZlibBuilder(StandardBuilder):
def build(self):
zlib_dir = self.standard_fetch_extract(
'http://downloads.sourceforge.net/project/libpng/zlib/%(my_version)s/zlib-%(my_version)s.tar.gz')
with in_dir(zlib_dir):
with self.execute_batch() as b:
b.add("nmake /f win32/Makefile.msc")
# libcurl loves its _a suffixes on static library names
b.add("cp zlib.lib zlib_a.lib")
# assemble dist
b.add('mkdir dist dist\\include dist\\lib dist\\bin')
b.add('cp *.lib *.exp dist/lib')
b.add('cp *.dll dist/bin')
b.add('cp *.h dist/include')
@property
def dll_paths(self):
return [
os.path.join(self.bin_path, 'zlib1.dll'),
]
class OpensslBuilder(StandardBuilder):
def build(self):
# another openssl gem:
# nasm output is redirected to NUL which ends up creating a file named NUL.
# however being a reserved file name this file is not deletable by
# ordinary tools.
nul_file = "openssl-%s-%s\\NUL" % (self.bconf.openssl_version, self.bconf.vc_tag)
check_call(['rm', '-f', nul_file])
openssl_dir = self.standard_fetch_extract(
'https://www.openssl.org/source/openssl-%(my_version)s.tar.gz')
with in_dir(openssl_dir):
with self.execute_batch() as b:
if self.bconf.openssl_version_tuple < (1, 1):
# openssl 1.0.2
b.add("patch -p0 < %s" %
require_file_exists(os.path.join(config.winbuild_patch_root, 'openssl-fix-crt-1.0.2.patch')))
else:
# openssl 1.1.0
b.add("patch -p0 < %s" %
require_file_exists(os.path.join(config.winbuild_patch_root, 'openssl-fix-crt-1.1.0.patch')))
if self.bconf.bitness == 64:
target = 'VC-WIN64A'
batch_file = 'do_win64a'
else:
target = 'VC-WIN32'
batch_file = 'do_nasm'
# msysgit perl has trouble with backslashes used in
# win64 assembly things in openssl 1.0.2
# and in x86 assembly as well in openssl 1.1.0;
# use ActiveState Perl
if not os.path.exists(config.activestate_perl_bin_path):
raise ValueError('activestate_perl_bin_path refers to a nonexisting path')
if not os.path.exists(os.path.join(config.activestate_perl_bin_path, 'perl.exe')):
raise ValueError('No perl binary in activestate_perl_bin_path')
b.add("set path=%s;%%path%%" % config.activestate_perl_bin_path)
b.add("perl -v")
openssl_prefix = os.path.join(os.path.realpath('.'), 'build')
# Do not want compression:
# https://en.wikipedia.org/wiki/CRIME
extras = ['no-comp']
if config.openssl_version_tuple >= (1, 1):
# openssl 1.1.0
# in 1.1.0 the static/shared selection is handled by
# invoking the right makefile
extras += ['no-shared']
# looks like openssl 1.1.0c does not derive
# --openssldir from --prefix, like its Configure claims,
# and like 1.0.2 does; provide a relative openssl dir
# manually
extras += ['--openssldir=ssl']
b.add("perl Configure %s %s --prefix=%s" % (target, ' '.join(extras), openssl_prefix))
if config.openssl_version_tuple < (1, 1):
# openssl 1.0.2
b.add("call ms\\%s" % batch_file)
b.add("nmake -f ms\\nt.mak")
b.add("nmake -f ms\\nt.mak install")
else:
# openssl 1.1.0
b.add("nmake")
b.add("nmake install")
# assemble dist
b.add('mkdir dist')
b.add('cp -r build/include build/lib dist')
class CaresBuilder(StandardBuilder):
def build(self):
cares_dir = self.standard_fetch_extract(
'http://c-ares.haxx.se/download/c-ares-%(my_version)s.tar.gz')
if self.bconf.cares_version == '1.12.0':
# msvc_ver.inc is missing in c-ares-1.12.0.tar.gz
# https://github.com/c-ares/c-ares/issues/69
fetch('https://raw.githubusercontent.com/c-ares/c-ares/cares-1_12_0/msvc_ver.inc',
archive='cares-1.12.0/msvc_ver.inc')
with in_dir(cares_dir):
with self.execute_batch() as b:
if self.bconf.cares_version == '1.10.0':
b.add("patch -p1 < %s" %
require_file_exists(os.path.join(config.winbuild_patch_root, 'c-ares-vs2015.patch')))
b.add("nmake -f Makefile.msvc")
# assemble dist
b.add('mkdir dist dist\\include dist\\lib')
if self.bconf.cares_version_tuple < (1, 14, 0):
subdir = 'ms%s0' % self.bconf.vc_version
else:
subdir = 'msvc'
b.add('cp %s/cares/lib-release/*.lib dist/lib' % subdir)
b.add('cp *.h dist/include')
class Libssh2Builder(StandardBuilder):
def build(self):
libssh2_dir = self.standard_fetch_extract(
'http://www.libssh2.org/download/libssh2-%(my_version)s.tar.gz')
with in_dir(libssh2_dir):
with self.execute_batch() as b:
if self.bconf.libssh2_version_tuple < (1, 8, 0) and self.bconf.vc_version == 'vc14':
b.add("patch -p0 < %s" %
require_file_exists(os.path.join(config.winbuild_patch_root, 'libssh2-vs2015.patch')))
zlib_builder = ZlibBuilder(bconf=self.bconf)
openssl_builder = OpensslBuilder(bconf=self.bconf)
vars = '''
OPENSSLINC=%(openssl_include_path)s
OPENSSLLIB=%(openssl_lib_path)s
ZLIBINC=%(zlib_include_path)s
ZLIBLIB=%(zlib_lib_path)s
WITH_ZLIB=1
BUILD_STATIC_LIB=1
''' % dict(
openssl_include_path=openssl_builder.include_path,
openssl_lib_path=openssl_builder.lib_path,
zlib_include_path=zlib_builder.include_path,
zlib_lib_path=zlib_builder.lib_path,
)
with open('win32/config.mk', 'r+') as cf:
contents = cf.read()
cf.seek(0)
cf.write(vars)
cf.write(contents)
b.add("nmake -f NMakefile")
# libcurl loves its _a suffixes on static library names
b.add("cp Release\\src\\libssh2.lib Release\\src\\libssh2_a.lib")
# assemble dist
b.add('mkdir dist dist\\include dist\\lib')
b.add('cp Release/src/*.lib dist/lib')
b.add('cp -r include dist')
class Nghttp2Builder(StandardBuilder):
CMAKE_GENERATORS = {
# Thanks cmake for requiring both version number and year,
# necessitating this additional map
'vc9': 'Visual Studio 9 2008',
'vc14': 'Visual Studio 14 2015',
}
def build(self):
nghttp2_dir = self.standard_fetch_extract(
'https://github.com/nghttp2/nghttp2/releases/download/v%(my_version)s/nghttp2-%(my_version)s.tar.gz')
# nghttp2 uses stdint.h which msvc9 does not ship.
# Amazingly, nghttp2 can seemingly build successfully without this
# file existing, but libcurl build subsequently fails
# when it tries to include stdint.h.
# Well, the reason why nghttp2 builds correctly is because it is built
# with the wrong compiler - msvc14 when 9 and 14 are both installed.
# nghttp2 build with msvc9 does fail without stdint.h existing.
if self.bconf.vc_version == 'vc9':
# https://stackoverflow.com/questions/126279/c99-stdint-h-header-and-ms-visual-studio
fetch('https://raw.githubusercontent.com/mattn/gntp-send/master/include/msinttypes/stdint.h')
with in_dir(nghttp2_dir):
shutil.copy('../stdint.h', 'lib/includes/stdint.h')
with in_dir(nghttp2_dir):
generator = self.CMAKE_GENERATORS[self.bconf.vc_version]
# Cmake also couldn't care less about the bitness I have configured in the
# environment since it ignores the environment entirely.
# Educate it on the required bitness by hand.
# https://stackoverflow.com/questions/28350214/how-to-build-x86-and-or-x64-on-windows-from-command-line-with-cmake#28370892
if self.bconf.bitness == 64:
generator += ' Win64'
with self.execute_batch() as b:
cmd = ' '.join([
'"%s"' % config.cmake_path,
# I don't know if this does anything, build type/config
# must be specified with --build option below.
'-DCMAKE_BUILD_TYPE=Release',
# This configures libnghttp2 only which is what we want.
# However, configure step still complains about all of the
# missing dependencies for nghttp2 server.
# And there is no indication whatsoever from configure step
# that this option is enabled, or that the missing
# dependency complaints can be ignored.
'-DENABLE_LIB_ONLY=1',
# This is required to get a static library built.
# However, even with this turned on there is still a DLL
# built - without an import library for it.
'-DENABLE_STATIC_LIB=1',
# And cmake ignores all visual studio environment variables
# and uses the newest compiler by default, which is great
# if one doesn't care what compiler their code is compiled with.
# https://stackoverflow.com/questions/6430251/what-is-the-default-generator-for-cmake-in-windows
'-G', '"%s"' % generator,
])
b.add('%s .' % cmd)
b.add(' '.join([
'"%s"' % config.cmake_path,
'--build', '.',
# this is what produces a release build
'--config', 'Release',
# this builds the static library.
# without this option cmake configures itself to be capable
# of building a static library but sometimes builds a DLL
# and sometimes builds a static library
# depending on compiler in use (vc9/vc14) or, possibly,
# phase of the moon.
'--target', 'nghttp2_static',
]))
# libcurl and its library name expectations
b.add('cp lib/Release/nghttp2.lib lib/Release/nghttp2_static.lib')
# assemble dist
b.add('mkdir dist dist\\include dist\\include\\nghttp2 dist\\lib')
b.add('cp lib/Release/*.lib dist/lib')
b.add('cp lib/includes/nghttp2/*.h dist/include/nghttp2')
if self.bconf.vc_version == 'vc9':
# stdint.h
b.add('cp lib/includes/*.h dist/include')
class LibiconvBuilder(StandardBuilder):
def build(self):
libiconv_dir = self.standard_fetch_extract(
'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-%(my_version)s.tar.gz')
with in_dir(libiconv_dir):
with self.execute_batch() as b:
b.add("env LD=link bash ./configure")
b.add(config.gmake_path)
class LibidnBuilder(StandardBuilder):
def build(self):
libidn_dir = self.standard_fetch_extract(
'https://ftp.gnu.org/gnu/libidn/libidn-%(my_version)s.tar.gz')
with in_dir(libidn_dir):
with self.execute_batch() as b:
b.add("env LD=link bash ./configure")
class LibcurlBuilder(StandardBuilder):
def build(self):
curl_dir = self.standard_fetch_extract(
'https://curl.haxx.se/download/curl-%(my_version)s.tar.gz')
with in_dir(os.path.join(curl_dir, 'winbuild')):
if self.bconf.vc_version == 'vc9':
# normaliz.lib in vc9 does not have the symbols libcurl
# needs for winidn.
# Handily we have a working normaliz.lib in vc14.
# Let's take the working one and copy it locally.
os.mkdir('support')
if self.bconf.bitness == 32:
shutil.copy(os.path.join(self.bconf.windows_sdk_path, 'lib', 'normaliz.lib'),
os.path.join('support', 'normaliz.lib'))
else:
shutil.copy(os.path.join(self.bconf.windows_sdk_path, 'lib', 'x64', 'normaliz.lib'),
os.path.join('support', 'normaliz.lib'))
with self.execute_batch() as b:
b.add("patch -p1 < %s" %
require_file_exists(os.path.join(config.winbuild_patch_root, 'libcurl-fix-zlib-references.patch')))
if self.use_dlls:
dll_or_static = 'dll'
else:
dll_or_static = 'static'
extra_options = ' mode=%s' % dll_or_static
if self.bconf.vc_version == 'vc9':
# use normaliz.lib from msvc14/more recent windows sdk
b.add("set lib=%s;%%lib%%" % os.path.abspath('support'))
if self.bconf.use_zlib:
zlib_builder = ZlibBuilder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % zlib_builder.include_path)
b.add("set lib=%%lib%%;%s" % zlib_builder.lib_path)
extra_options += ' WITH_ZLIB=%s' % dll_or_static
if self.bconf.use_openssl:
openssl_builder = OpensslBuilder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % openssl_builder.include_path)
b.add("set lib=%%lib%%;%s" % openssl_builder.lib_path)
extra_options += ' WITH_SSL=%s' % dll_or_static
if self.bconf.use_cares:
cares_builder = CaresBuilder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % cares_builder.include_path)
b.add("set lib=%%lib%%;%s" % cares_builder.lib_path)
extra_options += ' WITH_CARES=%s' % dll_or_static
if self.bconf.use_libssh2:
libssh2_builder = Libssh2Builder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % libssh2_builder.include_path)
b.add("set lib=%%lib%%;%s" % libssh2_builder.lib_path)
extra_options += ' WITH_SSH2=%s' % dll_or_static
if self.bconf.use_nghttp2:
nghttp2_builder = Nghttp2Builder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % nghttp2_builder.include_path)
b.add("set lib=%%lib%%;%s" % nghttp2_builder.lib_path)
extra_options += ' WITH_NGHTTP2=%s NGHTTP2_STATICLIB=1' % dll_or_static
if self.bconf.use_libidn:
libidn_builder = LibidnBuilder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % libidn_builder.include_path)
b.add("set lib=%%lib%%;%s" % libidn_builder.lib_path)
extra_options += ' WITH_LIBIDN=%s' % dll_or_static
if config.openssl_version_tuple >= (1, 1):
# openssl 1.1.0
# https://curl.haxx.se/mail/lib-2016-08/0104.html
# https://github.com/curl/curl/issues/984
# crypt32.lib: http://stackoverflow.com/questions/37522654/linking-with-openssl-lib-statically
extra_options += ' MAKE="NMAKE /e" SSL_LIBS="libssl.lib libcrypto.lib crypt32.lib"'
# https://github.com/curl/curl/issues/1863
extra_options += ' VC=%s' % self.bconf.vc_version[2:]
# curl uses winidn APIs that do not exist in msvc9:
# https://github.com/curl/curl/issues/1863
# We work around the msvc9 deficiency by using
# msvc14 normaliz.lib on vc9.
extra_options += ' ENABLE_IDN=yes'
b.add("nmake /f Makefile.vc %s" % extra_options)
# assemble dist - figure out where libcurl put its files
# and move them to a more reasonable location
with in_dir(curl_dir):
subdirs = sorted(os.listdir('builds'))
if len(subdirs) != 3:
raise Exception('Should be 3 directories here')
expected_dir = subdirs.pop(0)
for dir in subdirs:
if not dir.startswith(expected_dir):
raise Exception('%s does not start with %s' % (dir, expected_dir))
os.rename(os.path.join('builds', expected_dir), 'dist')
if self.bconf.vc_version == 'vc9':
# need this normaliz.lib to build pycurl later on
shutil.copy('winbuild/support/normaliz.lib', 'dist/lib/normaliz.lib')
# need libcurl.lib to build pycurl with --curl-dir argument
shutil.copy('dist/lib/libcurl_a.lib', 'dist/lib/libcurl.lib')
@property
def dll_paths(self):
return [
os.path.join(self.bin_path, 'libcurl.dll'),
]
class PycurlBuilder(Builder):
def __init__(self, **kwargs):
self.python_release = kwargs.pop('python_release')
super(PycurlBuilder, self).__init__(**kwargs)
# vc_version is specified externally for bconf/BuildConfig
assert self.bconf.vc_version == PYTHON_VC_VERSIONS[self.python_release]
@property
def python_path(self):
if config.build_wheels:
python_path = os.path.join(config.archives_path, 'venv-%s-%s' % (self.python_release, self.bconf.bitness), 'scripts', 'python')
else:
python_path = PythonBinary(self.python_release, self.bconf.bitness).executable_path
return python_path
@property
def platform_indicator(self):
platform_indicators = {32: 'win32', 64: 'win-amd64'}
return platform_indicators[self.bconf.bitness]
def build(self, targets):
libcurl_builder = LibcurlBuilder(bconf=self.bconf)
libcurl_dir = os.path.join(os.path.abspath(libcurl_builder.output_dir_path), 'dist')
dll_paths = libcurl_builder.dll_paths
if self.bconf.use_zlib:
zlib_builder = ZlibBuilder(bconf=self.bconf)
dll_paths += zlib_builder.dll_paths
dll_paths = [os.path.abspath(dll_path) for dll_path in dll_paths]
with in_dir(os.path.join('pycurl-%s' % self.bconf.pycurl_version)):
dest_lib_path = 'build/lib.%s-%s' % (self.platform_indicator,
self.python_release)
# exists for building additional targets for the same python version
mkdir_p(dest_lib_path)
if self.use_dlls:
for dll_path in dll_paths:
shutil.copy(dll_path, dest_lib_path)
with self.execute_batch() as b:
b.add("%s setup.py docstrings" % (self.python_path,))
if self.use_dlls:
libcurl_arg = '--use-libcurl-dll'
else:
libcurl_arg = '--libcurl-lib-name=libcurl_a.lib'
if self.bconf.use_openssl:
libcurl_arg += ' --with-openssl'
if config.openssl_version_tuple >= (1, 1):
libcurl_arg += ' --openssl-lib-name=""'
openssl_builder = OpensslBuilder(bconf=self.bconf)
b.add("set include=%%include%%;%s" % openssl_builder.include_path)
b.add("set lib=%%lib%%;%s" % openssl_builder.lib_path)
#if build_wheels:
#b.add("call %s" % os.path.join('..', 'venv-%s-%s' % (self.python_release, self.bconf.bitness), 'Scripts', 'activate'))
if config.build_wheels:
targets = targets + ['bdist_wheel']
if config.libcurl_version_tuple >= (7, 60, 0):
# As of 7.60.0 libcurl does not include its dependencies into
# its static libraries.
# libcurl_a.lib in 7.59.0 is 30 mb.
# libcurl_a.lib in 7.60.0 is 2 mb.
# https://github.com/curl/curl/pull/2474 is most likely culprit.
# As a result we need to specify all of the libraries that
# libcurl depends on here, plus the library paths,
# plus even windows standard libraries for good measure.
if self.bconf.use_zlib:
zlib_builder = ZlibBuilder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % zlib_builder.lib_path
libcurl_arg += ' --link-arg=zlib.lib'
if self.bconf.use_openssl:
openssl_builder = OpensslBuilder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % openssl_builder.lib_path
# openssl 1.1
libcurl_arg += ' --link-arg=libcrypto.lib'
libcurl_arg += ' --link-arg=libssl.lib'
libcurl_arg += ' --link-arg=crypt32.lib'
libcurl_arg += ' --link-arg=advapi32.lib'
if self.bconf.use_cares:
cares_builder = CaresBuilder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % cares_builder.lib_path
libcurl_arg += ' --link-arg=libcares.lib'
if self.bconf.use_libssh2:
libssh2_builder = Libssh2Builder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % libssh2_builder.lib_path
libcurl_arg += ' --link-arg=libssh2.lib'
if self.bconf.use_nghttp2:
nghttp2_builder = Nghttp2Builder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % nghttp2_builder.lib_path
libcurl_arg += ' --link-arg=nghttp2.lib'
if self.bconf.vc_version == 'vc9':
# this is for normaliz.lib
libcurl_builder = LibcurlBuilder(bconf=self.bconf)
libcurl_arg += ' --link-arg=/LIBPATH:%s' % libcurl_builder.lib_path
# We always use normaliz.lib, but it may come from
# "standard" msvc location or from libcurl's lib dir for msvc9
libcurl_arg += ' --link-arg=normaliz.lib'
libcurl_arg += ' --link-arg=user32.lib'
b.add("%s setup.py %s --curl-dir=%s %s" % (
self.python_path, ' '.join(targets), libcurl_dir, libcurl_arg))
if 'bdist' in targets:
zip_basename_orig = 'pycurl-%s.%s.zip' % (
self.bconf.pycurl_version, self.platform_indicator)
zip_basename_new = 'pycurl-%s.%s-py%s.zip' % (
self.bconf.pycurl_version, self.platform_indicator, self.python_release)
with zipfile.ZipFile('dist/%s' % zip_basename_orig, 'r') as src_zip:
with zipfile.ZipFile('dist/%s' % zip_basename_new, 'w') as dest_zip:
for name in src_zip.namelist():
parts = name.split('/')
while True:
popped = parts.pop(0)
if popped == 'python%s' % self.python_release.dotless or popped.startswith('venv-'):
break
assert len(parts) > 0
new_name = '/'.join(parts)
print('Recompressing %s -> %s' % (name, new_name))
member = src_zip.open(name)
dest_zip.writestr(new_name, member.read(), zipfile.ZIP_DEFLATED)
def dep_builders(bconf):
builders = []
if config.use_zlib:
builders.append(ZlibBuilder)
if config.use_openssl:
builders.append(OpensslBuilder)
if config.use_cares:
builders.append(CaresBuilder)
if config.use_libssh2:
builders.append(Libssh2Builder)
if config.use_nghttp2:
builders.append(Nghttp2Builder)
if config.use_libidn:
builders.append(LibiconvBuilder)
builders.append(LibidnBuilder)
builders.append(LibcurlBuilder)
builders = [
cls(bconf=bconf)
for cls in builders
]
return builders
def build_dependencies(config):
if config.use_libssh2:
if not config.use_zlib:
# technically we can build libssh2 without zlib but I don't want to bother
raise ValueError('use_zlib must be true if use_libssh2 is true')
if not config.use_openssl:
raise ValueError('use_openssl must be true if use_libssh2 is true')
if config.git_bin_path:
os.environ['PATH'] += ";%s" % config.git_bin_path
mkdir_p(config.archives_path)
with in_dir(config.archives_path):
for bconf in config.buildconfigs():
if opts.verbose:
print('Builddep for %s, %s-bit' % (bconf.vc_version, bconf.bitness))
for builder in dep_builders(bconf):
step(builder.build, (), builder.state_tag)
def build(config):
# note: adds git_bin_path to PATH if necessary, and creates archives_path
build_dependencies(config)
with in_dir(config.archives_path):
def prepare_pycurl():
#fetch('https://dl.bintray.com/pycurl/pycurl/pycurl-%s.tar.gz' % pycurl_version)
if os.path.exists('pycurl-%s' % config.pycurl_version):
# shutil.rmtree is incapable of removing .git directory because it contains
# files marked read-only (tested on python 2.7 and 3.6)
#shutil.rmtree('pycurl-%s' % config.pycurl_version)
rm_rf('pycurl-%s' % config.pycurl_version)
#check_call([tar_path, 'xf', 'pycurl-%s.tar.gz' % pycurl_version])
shutil.copytree('c:/dev/pycurl', 'pycurl-%s' % config.pycurl_version)
prepare_pycurl()
for bitness in config.bitnesses:
for python_release in config.python_releases:
targets = ['bdist', 'bdist_wininst', 'bdist_msi']
vc_version = PYTHON_VC_VERSIONS[python_release]
bconf = BuildConfig(bitness=bitness, vc_version=vc_version)
builder = PycurlBuilder(bconf=bconf, python_release=python_release)
builder.build(targets)
def python_metas():
metas = []
for version in config.python_versions:
parts = [int(part) for part in version.split('.')]
if parts[0] >= 3 and parts[1] >= 5:
ext = 'exe'
amd64_suffix = '-amd64'
else:
ext = 'msi'
amd64_suffix = '.amd64'
url_32 = 'https://www.python.org/ftp/python/%s/python-%s.%s' % (version, version, ext)
url_64 = 'https://www.python.org/ftp/python/%s/python-%s%s.%s' % (version, version, amd64_suffix, ext)
meta = dict(
version=version, ext=ext, amd64_suffix=amd64_suffix,
url_32=url_32, url_64=url_64,
installed_path_32 = 'c:\\dev\\32\\python%d%d' % (parts[0], parts[1]),
installed_path_64 = 'c:\\dev\\64\\python%d%d' % (parts[0], parts[1]),
)
metas.append(meta)
return metas
def download_pythons(config):
for meta in python_metas():
for bitness in config.bitnesses:
fetch_to_archives(meta['url_%d' % bitness])
def install_pythons(config):
for meta in python_metas():
for bitness in config.bitnesses:
if not os.path.exists(meta['installed_path_%d' % bitness]):
install_python(config, meta, bitness)
def fix_slashes(path):
return path.replace('/', '\\')
# http://eddiejackson.net/wp/?p=10276
def install_python(config, meta, bitness):
archive_path = fix_slashes(os.path.join(config.archives_path, os.path.basename(meta['url_%d' % bitness])))
if meta['ext'] == 'exe':
cmd = [archive_path]
else:
cmd = ['msiexec', '/i', archive_path, '/norestart']
cmd += ['/passive', 'InstallAllUsers=1',
'Include_test=0', 'Include_doc=0', 'Include_launcher=0',
'Include_ckltk=0',
'TargetDir=%s' % meta['installed_path_%d' % bitness],
]
sys.stdout.write('Installing python %s (%d bit)\n' % (meta['version'], bitness))
print(' '.join(cmd))
sys.stdout.flush()
check_call(cmd)
def download_bootstrap_python(config):
version = config.python_versions[-2]
url = 'https://www.python.org/ftp/python/%s/python-%s.msi' % (version, version)
fetch(url)
def install_virtualenv(config):
with in_dir(config.archives_path):
#fetch('https://pypi.python.org/packages/source/v/virtualenv/virtualenv-%s.tar.gz' % virtualenv_version)
fetch('https://pypi.python.org/packages/d4/0c/9840c08189e030873387a73b90ada981885010dd9aea134d6de30cd24cb8/virtualenv-15.1.0.tar.gz')
for bitness in config.bitnesses:
for python_release in config.python_releases:
print('Installing virtualenv %s for Python %s (%s bit)' % (config.virtualenv_version, python_release, bitness))
sys.stdout.flush()
untar('virtualenv-%s' % config.virtualenv_version)
with in_dir('virtualenv-%s' % config.virtualenv_version):
python_binary = PythonBinary(python_release, bitness)
cmd = [python_binary.executable_path, 'setup.py', 'install']
check_call(cmd)
def create_virtualenvs(config):
for bitness in config.bitnesses:
for python_release in config.python_releases:
print('Creating a virtualenv for Python %s (%s bit)' % (python_release, bitness))
sys.stdout.flush()
with in_dir(config.archives_path):
python_binary = PythonBinary(python_release, bitness)
venv_basename = 'venv-%s-%s' % (python_release, bitness)
cmd = [python_binary.executable_path, '-m', 'virtualenv', venv_basename]
check_call(cmd)
def assemble_deps(config):
rm_rf('deps')
os.mkdir('deps')
for bconf in config.buildconfigs():
print(bconf.vc_tag)
sys.stdout.flush()
dest = os.path.join('deps', bconf.vc_tag)
os.mkdir(dest)
for builder in dep_builders(bconf):
cp_r(builder.include_path, dest)
cp_r(builder.lib_path, dest)
with zipfile.ZipFile(os.path.join('deps', bconf.vc_tag + '.zip'), 'w', zipfile.ZIP_DEFLATED) as zip:
for root, dirs, files in os.walk(dest):
for file in files:
path = os.path.join(root, file)
zip_name = path[len(dest)+1:]
zip.write(path, zip_name)
def get_deps():
import struct
python_release = sys.version_info[:2]
vc_version = PYTHON_VC_VERSIONS['.'.join(map(str, python_release))]
bitness = struct.calcsize('P') * 8
vc_tag = '%s-%d' % (vc_version, bitness)
fetch('https://dl.bintray.com/pycurl/deps/%s.zip' % vc_tag)
check_call(['unzip', '-d', 'deps', vc_tag + '.zip'])
import optparse
parser = optparse.OptionParser()
parser.add_option('-b', '--bitness', help='Bitnesses build for, comma separated')
parser.add_option('-p', '--python', help='Python versions to build for, comma separated')
parser.add_option('-v', '--verbose', help='Print what is being done', action='store_true')
opts, args = parser.parse_args()
if opts.bitness:
chosen_bitnesses = [int(bitness) for bitness in opts.bitness.split(',')]
for bitness in chosen_bitnesses:
if bitness not in BITNESSES:
print('Invalid bitness %d' % bitness)
exit(2)
else:
chosen_bitnesses = BITNESSES
if opts.python:
chosen_pythons = opts.python.split(',')
chosen_python_versions = []
for python in chosen_pythons:
python = python.replace('.', '')
python = python[0] + '.' + python[1] + '.'
ok = False
for python_version in Config.python_versions:
if python_version.startswith(python):
chosen_python_versions.append(python_version)
ok = True
if not ok:
print('Invalid python %s' % python)
exit(2)
else:
chosen_python_versions = Config.python_versions
config = ExtendedConfig(
bitnesses=chosen_bitnesses,
python_versions=chosen_python_versions,
)
if len(args) > 0:
if args[0] == 'download':
download_pythons(config)
elif args[0] == 'bootstrap':
download_bootstrap_python(config)
elif args[0] == 'installpy':
install_pythons(config)
elif args[0] == 'builddeps':
build_dependencies(config)
elif args[0] == 'installvirtualenv':
install_virtualenv(config)
elif args[0] == 'createvirtualenvs':
create_virtualenvs(config)
elif args[0] == 'assembledeps':
assemble_deps(config)
elif args[0] == 'getdeps':
get_deps()
else:
print('Unknown command: %s' % args[0])
exit(2)
else:
build(config)
pycurl-7.43.0.2/PKG-INFO 0000644 0001750 0001750 00000011202 13304422066 013400 0 ustar me me 0000000 0000000 Metadata-Version: 1.1
Name: pycurl
Version: 7.43.0.2
Summary: PycURL -- A Python Interface To The cURL library
Home-page: http://pycurl.io/
Author: Oleg Pudeyev
Author-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 2.7 or 3.4 through 3.6.
- libcurl 7.19.0 or better.
Installation
------------
Download source and binary distributions from `PyPI`_ or `Bintray`_.
Binary wheels are now available for 32 and 64 bit Windows versions.
Please see `the installation documentation`_ for installation instructions.
.. _PyPI: https://pypi.python.org/pypi/pycurl
.. _Bintray: https://dl.bintray.com/pycurl/pycurl/
.. _the installation documentation: http://pycurl.io/docs/latest/install.html
Documentation
-------------
Documentation for the most recent PycURL release is available on
`PycURL website `_.
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
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
Classifier: Topic :: Internet :: WWW/HTTP
pycurl-7.43.0.2/ChangeLog 0000644 0001750 0001750 00000152504 13304422026 014064 0 ustar me me 0000000 0000000 Version 7.43.0.2 [requires libcurl-7.19.0 or better] - 2018-06-02
-----------------------------------------------------------------
* Official Windows builds now include HTTP 2 support via
libnghttp2 and international domain name support via WINIDN.
* Added perform_rb and perform_rs methods to Curl objects to
return response body as byte string and string, respectively.
* Added OPT_COOKIELIST constant for consistency with other
option constants.
* PycURL is now able to report errors triggered by libcurl
via CURLOPT_FAILONERROR mechanism when the error messages are
not decodable in Python's default encoding (GitHub issue #259).
* Added getinfo_raw method to Curl objects to return byte strings
as is from libcurl without attempting to decode them
(GitHub issue #493).
* When adding a Curl easy object to CurlMulti via add_handle,
the easy objects now have their reference counts increased so that
the application is no longer required to keep references to them
to keep them from being garbage collected (GitHub issue #171).
* PycURL easy, multi and share objects can now be weak referenced.
* Python 3.2 and 3.3 support officially dropped as those versions
are end of lifed.
* set_ca_certs now accepts byte strings as it should have been
all along.
* PycURL now skips automatic SSL backend detection if curl-config
indicates that libcurl is not built with SSL support, and will warn
if an SSL backend is explicitly specified in this case.
* PycURL now requires that SSL backend is determined by setup.py
to provide earlier failure compared to the existing warning
during compilation and failing during module import on mismatched
SSL backends.
* Use OpenSSL 1.1 and 1.0 specific APIs for controlling thread locks
depending on OpenSSL version (patch by Vitaly Murashev).
* Fixed a crash when closesocket callback failed (patch by
Gisle Vanem and toddrme2178).
* Added CURLOPT_PROXY_SSLCERT, CURLOPT_PROXY_SSLCERTTYPE,
CURLOPT_PROXY_SSLKEY, CURLOPT_PROXY_SSLKEYTYPE,
CURLOPT_PROXY_SSL_VERIFYPEER (libcurl 7.52.0+,
patch by Casey Miller).
* Added CURLOPT_PRE_PROXY (libcurl 7.52.0+, patch by ziggy).
* Support for Python 2.6 officially dropped.
* Added SOCKET_BAD constant and it is now recognized as a valid
return value from OPENSOCKET callback.
* BoringSSL is now recognized as equivalent to OpenSSL backend
(patch by Gisle Vanem).
Version 7.43.0.1 [requires libcurl-7.19.0 or better] - 2017-12-07
-----------------------------------------------------------------
* WRITEHEADER/WRITEFUNCTION and WRITEDATA/WRITEFUNCTION can now
be set on the same handle. The last call will take precedence over
previous calls. Previously some combinations were not allowed.
* Fixed a crash when using WRITEDATA with a file-like object followed
by WRITEDATA with a real file object (patch by Léo El Amri).
* Fixed a theoretical memory leak in module initialization (patch by
ideal).
* Added support for CURL_SSLVERSION_MAX_* constants (libcurl 7.52.0+,
patch by Jozef Melicher).
* Added support for CURLSSH_AUTH_AGENT (libcurl 7.28.0+,
patch by kxrd).
* Added support for CURLOPT_CONNECT_TO (patch by Iain R. Learmonth).
* Added support for CURLINFO_HTTP_VERSION (patch by Iain R. Learmonth).
* Fixed build against OpenSSL l.1 on Windows.
* Added set_ca_certs method to the Easy object to set CA certificates
from a string (OpenSSL only, patch by Lipin Dmitriy).
* Python 3.6 is now officially supported (patch by Samuel
Dion-Girardeau).
* Added support for CURLOPT_PROXY_CAPATH (libcurl 7.52.0+,
patch by Jan Kryl).
* C-Ares updated to 1.12.0 in Windows builds, fixing DNS resolution
issues on Windows (patch by Wei C).
* Added --openssl-lib-name="" option to support building against
OpenSSL 1.1.0 on Windows.
* Fixed a possible double free situation in all Curl objects
due to a misuse of the trashcan API (patch by Benjamin Peterson).
* High level Curl objects can now be reused.
* LARGE options fixed under Windows and Python 3 (INFILESIZE,
MAX_RECV_SPEED_LARGE, MAX_SEND_SPEED_LARGE, MAXFILESIZE,
POSTFILESIZE, RESUME_FROM).
* Fixed compilation on Solaris (patch by Yiteng Zhang).
* ENCODING option can now be unset (patch by Yves Bastide).
Version 7.43.0 [requires libcurl-7.19.0 or better] - 2016-02-02
---------------------------------------------------------------
* Added CURLINFO_RTSP_* constants (libcurl 7.20.0+).
* Added CURLOPT_XOAUTH2_BEARER (libcurl 7.33.0+).
* Added CURLOPT_SASL_IR (libcurl 7.31.0+).
* Added CURLOPT_LOGIN_OPTIONS (libcurl 7.34.0+).
* Added CURLOPT_FTP_USE_PRET (libcurl 7.20.0+).
* Added setopt_string method to Curl objects to set arbitrary
string options.
* Switched to Bintray for hosting release distributions.
* Added CURLOPT_DEFAULT_PROTOCOL (libcurl 7.45.0+).
* Added CURLOPT_TLSAUTH_* options (libcurl 7.21.4+).
* Added CURLPROTO_SMB and CURLPROTO_SMBS constants (libcurl 7.40.0+).
* Added CURL_SOCKOPT_* constants (libcurl 7.21.5+).
* Added CURL_HTTP_VERSION_2_0, CURL_HTTP_VERSION_2 and
CURL_HTTP_VERSION_2TLS constants for CURLOPT_HTTP_VERSION
(various libcurl versions required for these).
* winbuild.py can now build binary wheels on Windows.
* Added failed memory allocation handling during SSL lock initialization.
* CURLOPT_IOCTLDATA option support has been removed.
This option is used internally by PycURL and is not settable by
applications.
* HTTPHEADER and PROXYHEADER options can now be unset.
* Added CURLPIPE_* constants (libcurl 7.43.0+).
* Added CURLOPT_PIPEWAIT (libcurl 7.43.0+).
* Added CURLOPT_PATH_AS_IS (libcurl 7.42.0+).
* Added CURLOPT_PROXYHEADER and CURLOPT_HEADEROPT as well as
CURLHEADER_UNIFIED and CURLHEADER_SEPARATE (libcurl 7.37.0+).
* Added CURLOPT_EXPECT_100_TIMEOUT_MS (libcurl 7.36.0+).
* Added CURLOPT_XFERINFOFUNCTION (libcurl 7.32.0+).
* Added CURLM_ADDED_ALREADY error constant (libcurl 7.32.1+).
* Added remaining CURLE_* constants through libcurl 7.46.0.
* Unbroken `curl' module import on Windows - apparently Windows now
has a `signal' Python module but no `SIGPIPE' (patch by Gabi Davar).
* Added CURLMOPT_PIPELINING_SITE_BL and CURLMOPT_PIPELINING_SERVER_BL
options (libcurl 7.30.0+).
* Added CURLOPT_TCP_KEEPALIVE, CURLOPT_TCP_KEEPIDLE and
CURLOPT_TCP_KEEPINTVL options (libcurl 7.25.0+).
* Added CURLOPT_ACCEPTTIMEOUT_MS (libcurl 7.24.0+).
* Added CURLOPT_ACCEPT_ENCODING and CURLOPT_TRANSFER_ENCODING
options (libcurl 7.21.6+).
* OPENSOCKETFUNCTION callback for AF_UNIX sockets was mistakenly
invoked with the address as a `string' rather than `bytes' on
Python 3. The callback now receives a `bytes' instance as was
documented.
Version 7.21.5 [requires libcurl-7.19.0 or better] - 2016-01-05
---------------------------------------------------------------
* --with-openssl and its --win-ssl alias setup.py options are now
accepted under Windows in order to use OpenSSL's crypto locks
when building against OpenSSL.
* --with-openssl added as an alias for --with-ssl option to setup.py.
* Official Windows builds are now linked against C-Ares and libssh2.
* Official Windows builds are now linked against OpenSSL instead of
WinSSL.
* Official Windows builds are now statically linked against
their dependencies (libcurl and zlib).
* Added CURLOPT_USE_SSL and CURLUSESSL_* constants.
* Added CURLOPT_APPEND, CURLOPT_COOKIESESSION, CURLOPT_DIRLISTONLY,
CURLOPT_KEYPASSWD, CURLOPT_TELNETOPTIONS.
* Several CURLE_* and CURLM_* constants added.
* Add VERSION_* constants, corresponding to CURL_VERSION_*.
* Breaking change: OPENSOCKETFUNCTION callback API now mirrors that
of libcurl:
1. The callback now takes two arguments, `purpose' and `address`.
Previously the callback took `family', `socktype', `protocol`
and `addr' arguments.
2. The second argument to the callback, `address', is a
`namedtuple' with `family', `socktype', `protocol' and
`addr' fields.
3. `addr' field on `address' for AF_INET6 family addresses is a
4-tuple of (address, port, flow info, scope id) which matches
Python's `socket.getaddrinfo' API.
It seems that libcurl may mishandle error return from an
opensocket callback, as would happen when code written for
pre-PycURL 7.21.5 API is run with PycURL 7.21.5 or newer,
resulting in the application hanging.
* OPENSOCKETFUNCTION callback can now be unset.
* Added CURLOPT_CLOSESOCKETFUNCTION (libcurl 7.21.7+).
CURLOPT_CLOSESOCKETDATA is used internally by PycURL.
* Added CURLOPT_SOCKOPTFUNCTION. CURLOPT_SOCKOPTDATA is used
internally by PycURL.
* Added CURLOPT_SSH_KEYFUNCTION (libcurl 7.19.6+).
CURLOPT_SSH_KEYDATA is used internally by PycURL.
* Added CURLOPT_SSL_OPTIONS (libcurl 7.25.0+).
* Added CURLOPT_KRBLEVEL.
* Added CURLOPT_SSL_FALSESTART (libcurl 7.42.0+).
* Added CURLOPT_SSL_ENABLE_NPN (libcurl 7.36.0+).
* Added CURLOPT_SSL_ENABLE_ALPN (libcurl 7.36.0+).
* Added CURLOPT_UNIX_SOCKET_PATH (libcurl 7.40.0+).
* Added CURLOPT_WILDCARDMATCH (libcurl 7.21.0+).
* C module initialization changed to raise exceptions on failure
rather than trigger a fatal error and abort the Python interpreter.
* Added CURLOPT_PINNEDPUBLICKEY (libcurl 7.39.0-7.44.0+
depending on SSL backend and encoding algorithm).
* Fixed incorrect detection of libcurl 7.19.5 and 7.19.6
(thanks to bataniya).
Version 7.19.5.3 [requires libcurl-7.19.0 or better] - 2015-11-03
-----------------------------------------------------------------
* python and nosetests binaries can now be overridden when running
the test suite (patch by Kamil Dudka).
* Files needed to run the test suite are distributed in sdist
(patch by Kamil Dudka).
Version 7.19.5.2 [requires libcurl-7.19.0 or better] - 2015-11-02
-----------------------------------------------------------------
* C sources made 64-bit clean on Windows.
* Support for building against Python 3.5 added to winbuild.py.
* Fixed build on Windows when using MS SDK 8.1+ or MSVC 14/2015
(patch by Gisle Vanem).
* Added automatic SSL library detection on CentOS 6 by loading
libcurl shared library in setup.py. This automatic detection is
meant to permit installing pycurl seamlessly via `pip install pycurl`
on CentOS; as such, it is only employed when no other configuration
options or configuration environment variables are given to setup.py
(original patch by Francisco Alves).
* Added --libcurl-dll option to setup.py to take SSL library
information out of libcurl shared library (original patch by
Francisco Alves). This option is only usable
with Python 2.5 or higher.
* --with-ssl, --with-gnutls and --with-nss options to setup.py now
result in PycURL explicitly linking against the respective SSL
library. Previously setup.py relied on curl-config to supply the
needed libraries in this case.
* List and tuples are now accepted in all positions of HTTPPOST
option values.
* Tuples are now accepted for options taking list values (e.g.
HTTPHEADER).
* Fixed a use after free in HTTPPOST when using FORM_BUFFERPTR with
a Unicode string (patch by Clint Clayton).
* Fixed a memory leak in HTTPPOST for multiple FORM_BUFFERPTR
(patch by Clint Clayton).
* CURLMOPT_* option constants were mistakenly defined on Curl
instances but not on CurlMulti instances. These option constants
are now defined on CurlMulti instances and on pycurl module,
but not on Curl instances.
* Fixed several memory leaks when setting string options to
Unicode values failed.
* Fixed a memory leak when using POSTFIELDS with unicode objects
on Python 2 (patch by Clint Clayton).
* Official support for Python 2.4 and 2.5 dropped. PycURL is no
longer tested against these Python versions on Travis.
* Added CURLAUTH_NEGOTIATE (libcurl 7.38.0+), CURLAUTH_NTLM_WB
(libcurl 7.22.0+), CURLAUTH_ONLY (libcurl 7.21.3+),
* Added CURLOPT_SERVICE_NAME (libcurl 7.43.0+).
* Added CURLOPT_PROXY_SERVICE_NAME (libcurl 7.43.0+).
* Added CURLE_SSL_CRL_BADFILE, CURLE_SSL_INVALIDCERTSTATUS
(libcurl 7.41.0+), CURLE_SSL_ISSUER_ERROR and
CURLE_SSL_PINNEDPUBKEYNOTMATCH (libcurl 7.39.0+).
* Added CURLOPT_SSL_VERIFYSTATUS (libcurl 7.41.0+).
* Added CURL_SSLVERSION_TLSv1_0, CURL_SSLVERSION_TLSv1_1
and CURL_SSLVERSION_TLSv1_2 (libcurl 7.34.0+).
* The second argument of DEBUGFUNCTION callback is now of type bytes on
Python 3. When response body contains non-ASCII data and
DEBUGFUNCTION is enabled, this argument would receive non-ASCII data.
Which encoding this data is in is unknown by PycURL, and e.g. in
the case of HTTP requires parsing response headers. GitHub issue
#210, patch by Barry Warsaw with help from Gregory Petukhov.
* Fixed build on GCC 4.4.5 (patch by Travis Jensen).
* Added CURLOPT_GSSAPI_DELEGATION, CURLGSSAPI_DELEGATION_FLAG,
CURLGSSAPI_DELEGATION_NONE and CURLGSSAPI_DELEGATION_POLICY_FLAG
(libcurl 7.22.0+, patch by Dmitry Ketov).
Version 7.19.5.1 [requires libcurl-7.19.0 or better] - 2015-01-06
-----------------------------------------------------------------
* Added CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5_HOSTNAME.
* setup.py now prints PycURL-specific option help when -h is used.
* LibreSSL is now supported (patch by JiCiT).
* Fixed an oversight that broke PycURL building against libcurl 7.19.4
through 7.21.1. The bug was introduced in PycURL 7.19.5.
* Tests are now included in source distributions again, thanks to
Kamil Dudka and Johan Bergstroem.
* Added CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT (libcurl 7.20.0+)
and CURLOPT_MAIL_AUTH (libcurl 7.25.0+).
Version 7.19.5 [requires libcurl-7.21.2 or better] - 2014-07-12
---------------------------------------------------------------
* Tests removed from source and binary distributions.
* Documentation greatly improved. Quickstart guide added.
* pycurl.Curl, pycurl.CurlMulti and pycurl.CurlShare are now classes
rather than factory functions. Previously, the classes were "hidden"
(they were accessible as e.g. type(pycurl.Curl()), but could not be
instantiated, nor could class methods be obtained from the classes.
Please see this mailing list post for further information:
https://curl.haxx.se/mail/curlpython-2014-06/0004.html
* When passing a file-like object to READDATA option, PycURL was
mistakenly looking for write method on this object. Now read method
is looked up, as would be expected.
* Python 3.4 is now officially supported.
* Windows packages now build libcurl against zlib.
* CherryPy is no longer required for the test suite, ssl module from
the Python standard library is used instead.
* Fixed a reference leak of SOCKET and TIMER callbacks on
CurlMulti instances, thanks to Ben Darnell.
* Fixed build against openssl on cygwin, where pycurl needs to link
against libcrypto rather than libssl.
* Added CURLOPT_SSH_KNOWNHOSTS (libcurl 7.19.6+).
* Added CURLE_FTP_ACCEPT_FAILED (libcurl 7.24.0+).
* Added CURLE_NOT_BUILT_IN and CURLE_UNKNOWN_OPTION (libcurl 7.21.5+).
* Added CURL_SEEKFUNC_OK, CURL_SEEKFUNC_FAIL and
CURL_SEEKFUNC_CANTSEEK. All contstants require libcurl 7.19.5+;
numeric values of CURL_SEEKFUNC_OK and CURL_SEEKFUNC_FAIL were
understood earlier but constants only exist as of libcurl 7.19.5.
* Added CURLINFO_CONDITION_UNMET (libcurl 7.19.4+).
* Added CURLPROXY_HTTP_1_0 (libcurl 7.19.4+).
* Added CURLOPT_SOCKS5_GSSAPI_SERVICE and
CURLOPT_SOCKS5_GSSAPI_NEC (libcurl 7.19.4+).
* Added CURLOPT_TFTP_BLKSIZE (libcurl 7.19.4+).
* Added CURLOPT_PROTOCOLS, CURLOPT_REDIR_PROTOCOLS and associated
CURLPROTO_* constants, which require libcurl 7.19.4+.
* Fixed a reference leak of OPENSOCKET and SEEK callbacks, thanks to
Ben Darnell.
* C source is now split into several files.
* Documentation is now processed by sphinx.
Version 7.19.3.1 [requires libcurl-7.19.0 or better] - 2014-02-05
-----------------------------------------------------------------
* Added --avoid-stdio setup.py option to avoid passing FILE
pointers from Python to libcurl. Applies to Python 2 only.
* Added CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE,
CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, CURLMOPT_MAX_HOST_CONNECTIONS
CURLMOPT_MAX_PIPELINE_LENGTH, CURLMOPT_MAX_TOTAL_CONNECTIONS
multi options (patch by Jakob Truelsen).
* SSL detection logic changed to consult `curl-config --static-libs`
even if `curl-config --libs` succeeded. This should achieve
pre-7.19.3 behavior with respect to automatic SSL detection
(patch by Andjelko Horvat).
Version 7.19.3 [requires libcurl-7.19.0 or better] - 2014-01-09
---------------------------------------------------------------
* Added CURLOPT_NOPROXY.
* Added CURLINFO_LOCAL_PORT, CURLINFO_PRIMARY_PORT and
CURLINFO_LOCAL_IP (patch by Adam Jacob Muller).
* When running on Python 2.x, for compatibility with Python 3.x,
Unicode strings containing ASCII code points only are now accepted
in setopt() calls.
* PycURL now requires that compile time SSL backend used by libcurl
is the same as the one used at runtime. setup.py supports
--with-ssl, --with-gnutls and --with-nss options like libcurl does,
to specify which backend libcurl uses. On some systems PycURL can
automatically figure out libcurl's backend.
If the backend is not one for which PycURL provides crypto locks
(i.e., any of the other backends supported by libcurl),
no runtime SSL backend check is performed.
* Default PycURL user agent string is now built at runtime, and will
include the user agent string of libcurl loaded at runtime rather
than the one present at compile time.
* PycURL will now use WSAduplicateSocket rather than dup on Windows
to duplicate sockets obtained from OPENSOCKETFUNCTION.
Using dup may have caused crashes, OPENSOCKETFUNCTION should
now be usable on Windows.
* A new script, winbuild.py, was added to build PycURL on Windows
against Python 2.6, 2.7, 3.2 and 3.3.
* Added CURL_LOCK_DATA_SSL_SESSION (patch by Tom Pierce).
* Added E_OPERATION_TIMEDOUT (patch by Romuald Brunet).
* setup.py now handles --help argument and will print PycURL-specific
configuration options in addition to distutils help.
* Windows build configuration has been redone:
PYCURL_USE_LIBCURL_DLL #define is gone, use --use-libcurl-dll
argument to setup.py to build against a libcurl DLL.
CURL_STATICLIB is now #defined only when --use-libcurl-dll is not
given to setup.py, and PycURL is built against libcurl statically.
--libcurl-lib-name option can be used to override libcurl import
library name.
* Added CURLAUTH_DIGEST_IE as pycurl.HTTPAUTH_DIGEST_IE.
* Added CURLOPT_POSTREDIR option and CURL_REDIR_POST_301,
CURL_REDIR_POST_302, CURL_REDIR_POST_303 and CURL_REDIR_POST_ALL
constants. CURL_REDIR_POST_303 requires libcurl 7.26.0 or higher,
all others require libcurl 7.19.1 or higher.
* As part of Python 3 support, WRITEDATA option now accepts
any object with a write method on Python 2 and Python 3.
For non-file objects, c.setopt(c.WRITEDATA, buf) is equivalent to
c.setopt(c.WRITEFUNCTION, buf.write).
* PycURL now supports Python 3.1 through 3.3. Python 3.0 might
work but it appears to ship with broken distutils, making virtualenv
not function on it.
* PycURL multi objects now have the multi constants defined on them.
Previously the constants were only available on pycurl module.
The new behavior matches that of curl and share objects.
* PycURL share objects can now be closed via the close() method.
* PycURL will no longer call `curl-config --static-libs` if
`curl-config --libs` succeeds and returns output.
Systems on which neither `curl-config --libs` nor
`curl-config --static-libs` do the right thing should provide
a `curl-config` wrapper that is sane.
* Added CURLFORM_BUFFER and CURLFORM_BUFFERPTR.
* pycurl.version and user agent string now include both
PycURL version and libcurl version as separate items.
* Added CURLOPT_DNS_SERVERS.
* PycURL can now be dynamically linked against libcurl on Windows
if PYCURL_USE_LIBCURL_DLL is #defined during compilation.
* Breaking change: opensocket callback now takes an additional
(address, port) tuple argument. Existing callbacks will need to
be modified to accept this new argument.
https://github.com/pycurl/pycurl/pull/18
Version 7.19.0.3 [requires libcurl-7.19.0 or better] - 2013-12-24
-----------------------------------------------------------------
* Re-release of 7.19.0.2 with minor changes to build Windows packages
due to botched 7.19.0.2 files on PyPi.
https://curl.haxx.se/mail/curlpython-2013-12/0021.html
Version 7.19.0.2 [requires libcurl-7.19.0 or better] - 2013-10-08
-----------------------------------------------------------------
* Fixed a bug in a commit made in 2008 but not released until 7.19.0.1
which caused CURLOPT_POSTFIELDS to not correctly increment reference
count of the object being given as its argument, despite libcurl not
copying the data provided by said object.
* Added support for libcurl pause/unpause functionality,
via curl_easy_pause call and returning READFUNC_PAUSE from
read callback function.
Version 7.19.0.1 [requires libcurl-7.19.0 or better] - 2013-09-23
-----------------------------------------------------------------
* Test matrix tool added to test against all supported Python and
libcurl versions.
* Python 2.4 is now the minimum required version.
* Source code, bugs and patches are now kept on GitHub.
* Added CURLINFO_CERTINFO and CURLOPT_CERTINFO.
* Added CURLOPT_RESOLVE.
* PycURL can now be used with Python binaries without thread
support.
* gcrypt is no longer initialized when a newer version of gnutls
is used.
* Marked NSS as supported.
* Fixed relative URL request logic.
* Fixed a memory leak in util_curl_init.
* Added CURLOPT_USERNAME and CURLOPT_PASSWORD.
* Fixed handling of big timeout values.
* Added GLOBAL_ACK_EINTR.
* setopt(..., None) can be used as unsetopt().
* CURLOPT_RANGE can now be unset.
* Write callback can return -1 to signal user abort.
* Reorganized tests into an automated test suite.
* Added CURLOPT_SEEKFUNCTION and CURLOPT_SEEKDATA.
* Cleaned up website.
* Fix pycurl.reset() (patch by ).
* Fix install routine in setup.py where
certain platforms (Solaris, Mac OSX, etc)
would search for a static copy of libcurl (dbp).
* Fixed build on OpenSolaris 0906 and other platforms on which
curl-config does not have a --static-libs option.
* No longer keep string options copies in the
Curl Python objects, since string options are
now managed by libcurl.
Version 7.19.0 [requires libcurl-7.19.0 or better]
--------------------------------------------------
* Added CURLFILE, ADDRESS_SCOPE and ISSUERCERT options,
as well as the APPCONNECT_TIME info.
* Added PRIMARY_IP info (patch by
Yuhui H ).
* Added support for curl_easy_reset through a
new 'reset' method on curl objects
(patch by Nick Pilon ).
* Added support for OPENSOCKET callbacks.
See 'tests/test_opensocket.py' for example
usage (patch by Thomas Hunger ).
Version 7.18.2
--------------
* Added REDIRECT_URL info and M_MAXCONNECTS option
(patch by Yuhui H ).
* Added socket_action() method to CurlMulti objects.
See 'tests/test_multi_socket_select.py' for example
usage (patch by Yuhui H ).
* Added AUTOREFERER option.
* Allow resetting some list operations (HTTPHEADER,
QUOTE, POSTQUOTE, PREQUOTE) by passing an empty
list to setopt (patch by Jim Patterson).
Version 7.18.1
--------------
* Added POST301, SSH_HOST_PUBLIC_KEY_MD5,
COPYPOSTFIELDS and PROXY_TRANSFER_MODE options.
* Check for static libs in setup.py to better detect
whether libcurl was linked with OpenSSL or GNUTLS.
* PycURL is now dual licensed under the LGPL and
a license similar to the cURL license (an MIT/X
derivative).
Version 7.16.4
--------------
* Allow any callable object as the callback function.
This change comes handy when you would like to use objects
which are callable but are not functions or methods, for
example those objects created by the functions in the functools
module (patch by Daniel Pena Arteaga ).
* Added NEW_DIRECTORY_PERMS and NEW_FILE_PERMS options.
Version 7.16.2.1
----------------
* Added IOCMD_NOP and IOCMD_RESTARTREAD for ioctl callback
handling (patch by Mark Eichin).
* Use Py_ssize_t where appropriate for Python 2.5 and 64-bit
compatibility. This fixes the problem reported by Aaron
Hill, where the exception "pycurl.error: (2, '')" is thrown
when calling setopt(pycurl.POSTFIELDS,...) on 64-bit
platforms.
Version 7.16.2
--------------
* Added options HTTP_TRANSFER_DECODING, HTTP_CONTENT_DECODING,
TIMEOUT_MS, CONNECTTIMEOUT_MS from libcurl 7.16.2.
* Right-strip URLs read from files in the test scripts
to avoid sending requests with '\n' at the end.
Version 7.16.1
--------------
* Added constants for all libcurl (error) return codes. They
are named the same as the macro constants in curl.h but prefixed
with E_ instead of CURLE. Return codes for the multi API are
prefixed with M_ instead of CURLM.
* Added CURLOPT_FTP_SSL_CCC, CURLOPT_SSH_PUBLIC_KEYFILE,
CURLOPT_SSH_PRIVATE_KEYFILE, CURLOPT_SSH_AUTH_TYPES.
* Removed CLOSEPOLICY and friends since this option is now
deprecated in libcurl.
* Set the _use_datetime attribute on the CURLTransport class
to unbreak xmlrpc_curl.py on Python 2.5.
Version 7.16.0 [no public release]
--------------
* Added CURLOPT_SSL_SESSIONID_CACHE.
* Removed SOURCE_* options since they are no longer
supported by libcurl.
Version 7.15.5.1
----------------
* Added test for basic ftp usage (tests/test_ftp.py).
* Fix broken ssl mutex lock function when using
GNU TLS (Debian bug #380156, fix by Bastian Kleineidam)
Version 7.15.5
--------------
* Added CURLOPT_FTP_ALTERNATIVE_TO_USER,
CURLOPT_MAX_SEND_SPEED_LARGE,
and CURLOPT_MAX_RECV_SPEED_LARGE.
Version 7.15.4.2
----------------
* Use SSL locking callbacks, fixes random
crashes for multithreaded SSL connections
(patch by Jayne ).
Version 7.15.4.1
----------------
* Fixed compilation problem with C compilers
not allowing declarations in the middle of
code blocks (patch by
K.S.Sreeram ).
* Fixed bug in curl_multi_fdset wrapping,
max_fd < 0 is not an error (patch by
K.S.Sreeram ).
Version 7.15.4
--------------
* Added support for libcurl shares, patch from
Victor Lascurain . See the
file tests/test_share.py for example usage.
* Added support for CURLINFO_FTP_ENTRY_PATH.
Version 7.15.2
--------------
* Added CURLOPT_CONNECT_ONLY, CURLINFO_LASTSOCKET,
CURLOPT_LOCALPORT and CURLOPT_LOCALPORTRANGE.
Version 7.15.1
--------------
2006-01-31 Kjetil Jacobsen
* Fixed memory leak for getinfo calls that return a
list as result. Patch by Paul Pacheco.
Version 7.15.0
--------------
2005-10-18 Kjetil Jacobsen
* Added CURLOPT_FTP_SKIP_PASV_IP.
Version 7.14.1
--------------
2005-09-05 Kjetil Jacobsen
* Added CURLOPT_IGNORE_CONTENT_LENGTH, CURLOPT_COOKIELIST as
COOKIELIST and CURLINFO_COOKIELIST as INFO_COOKIELIST.
Version 7.14.0
--------------
2005-05-18 Kjetil Jacobsen
* Added missing information returned from the info() method
in the high-level interface.
* Added the FORM_FILENAME option to the CURLFORM API
with HTTPPOST.
Version 7.13.2
--------------
2005-03-30 Kjetil Jacobsen
* Unbreak tests/test_gtk.py and require pygtk >= 2.0.
2005-03-15 Kjetil Jacobsen
* Cleaned up several of the examples.
2005-03-11 Kjetil Jacobsen
* WARNING: multi.select() now requires the previously optional
timeout parameter. Updated the tests and examples to reflect
this change. If the timeout is not set, select could block
infinitely and cause problems for the internal timeout handling
in the multi stack. The problem was identified by
.
Version 7.13.1
--------------
2005-03-04 Kjetil Jacobsen
* Use METH_NOARGS where appropriate.
2005-03-03 Kjetil Jacobsen
* Added support for CURLFORM API with HTTPPOST: Supports a
a tuple with pairs of options and values instead of just
supporting string contents. See tests/test_post2.py
for example usage. Options are FORM_CONTENTS, FORM_FILE and
FORM_CONTENTTYPE, corresponding to the CURLFORM_* options,
and values are strings.
2005-02-13 Markus F.X.J. Oberhumer
* Read callbacks (pycurl.READFUNCTION) can now return
pycurl.READFUNC_ABORT to immediately abort the current transfer.
* The INFILESIZE, MAXFILESIZE, POSTFIELDSIZE and RESUME_FROM
options now automatically use the largefile version to handle
files > 2GB.
* Added missing pycurl.PORT constant.
Version 7.13.0
--------------
2005-02-10 Kjetil Jacobsen
* Added file_upload.py to examples, shows how to upload
a file.
* Added CURLOPT_IOCTLFUNCTION/DATA.
* Added options from libcurl 7.13.0: FTP_ACCOUNT, SOURCE_URL,
SOURCE_QUOTE.
* Obsoleted options: SOURCE_HOST, SOURCE_PATH, SOURCE_PORT,
PASV_HOST.
Version 7.12.3
--------------
2004-12-22 Markus F.X.J. Oberhumer
* Added CURLINFO_NUM_CONNECTS and CURLINFO_SSL_ENGINES.
* Added some other missing constants.
* Updated pycurl.version_info() to return a 12-tuple
instead of a 9-tuple.
Version 7.12.2
--------------
2004-10-15 Kjetil Jacobsen
* Added CURLOPT_FTPSSLAUTH (and CURLFTPAUTH_*).
* Added CURLINFO_OS_ERRNO.
2004-08-17 Kjetil Jacobsen
* Use LONG_LONG instead of PY_LONG_LONG to make pycurl compile
on Python versions < 2.3 (fix from Domenico Andreoli
).
Version 7.12.1
--------------
2004-08-02 Kjetil Jacobsen
* Added INFOTYPE_SSL_DATA_IN/OUT.
2004-07-16 Markus F.X.J. Oberhumer
* WARNING: removed deprecated PROXY_, TIMECOND_ and non-prefixed
INFOTYPE constant names. See ChangeLog entry 2003-06-10.
2004-06-21 Kjetil Jacobsen
* Added test program for HTTP post using the read callback (see
tests/test_post3.py for details).
* Use the new CURL_READFUNC_ABORT return code where appropriate
to avoid hanging in perform() when read callbacks are used.
* Added support for libcurl 7.12.1 CURLOPT features:
SOURCE_HOST, SOURCE_USERPWD, SOURCE_PATH, SOURCE_PORT,
PASV_HOST, SOURCE_PREQUOTE, SOURCE_POSTQUOTE.
2004-06-08 Markus F.X.J. Oberhumer
* Setting CURLOPT_POSTFIELDS now allows binary data and
automatically sets CURLOPT_POSTFIELDSIZE for you. If you really
want a different size you have to manually set POSTFIELDSIZE
after setting POSTFIELDS.
(Based on a patch by Martin Muenstermann).
2004-06-05 Markus F.X.J. Oberhumer
* Added stricter checks within the callback handlers.
* Unify the behaviour of int and long parameters where appropriate.
Version 7.12
------------
2004-05-18 Kjetil Jacobsen
* WARNING: To simplify code maintenance pycurl now requires
libcurl 7.11.2 and Python 2.2 or newer to work.
* GC support is now always enabled.
Version 7.11.3
--------------
2004-04-30 Kjetil Jacobsen
* Do not use the deprecated curl_formparse function.
API CHANGE: HTTPPOST now takes a list of tuples where each
tuple contains a form name and a form value, both strings
(see test/test_post2.py for example usage).
* Found a possible reference count bug in the multithreading
code which may have contributed to the long-standing GC
segfault which has haunted pycurl. Fingers crossed.
Version 7.11.2
--------------
2004-04-21 Kjetil Jacobsen
* Added support for libcurl 7.11.2 CURLOPT features:
CURLOPT_TCP_NODELAY.
2004-03-25 Kjetil Jacobsen
* Store Python longs in off_t with PyLong_AsLongLong instead
of PyLong_AsLong. Should make the options which deal
with large files behave a little better. Note that this
requires the long long support in Python 2.2 or newer to
work properly.
Version 7.11.1
--------------
2004-03-16 Kjetil Jacobsen
* WARNING: Removed support for the PASSWDFUNCTION callback, which
is no longer supported by libcurl.
2004-03-15 Kjetil Jacobsen
* Added support for libcurl 7.11.1 CURLOPT features:
CURLOPT_POSTFIELDSIZE_LARGE.
Version 7.11.0
--------------
2004-02-11 Kjetil Jacobsen
* Added support for libcurl 7.11.0 CURLOPT features:
INFILESIZE_LARGE, RESUME_FROM_LARGE, MAXFILESIZE_LARGE
and FTP_SSL.
* Circular garbage collection support can now be enabled or
disabled by passing the '--use-gc=[1|0]' parameter to setup.py
when building pycurl.
* HTTP_VERSION options are known as CURL_HTTP_VERSION_NONE,
CURL_HTTP_VERSION_1_0, CURL_HTTP_VERSION_1_1 and
CURL_HTTP_VERSION_LAST.
2003-11-16 Markus F.X.J. Oberhumer
* Added support for these new libcurl 7.11.0 features:
CURLOPT_NETRC_FILE.
Version 7.10.8
--------------
2003-11-04 Markus F.X.J. Oberhumer
* Added support for these new libcurl 7.10.8 features:
CURLOPT_FTP_RESPONSE_TIMEOUT, CURLOPT_IPRESOLVE,
CURLOPT_MAXFILESIZE,
CURLINFO_HTTPAUTH_AVAIL, CURLINFO_PROXYAUTH_AVAIL,
CURL_IPRESOLVE_* constants.
* Added support for these new libcurl 7.10.7 features:
CURLOPT_FTP_CREATE_MISSING_DIRS, CURLOPT_PROXYAUTH,
CURLINFO_HTTP_CONNECTCODE.
2003-10-28 Kjetil Jacobsen
* Added missing CURLOPT_ENCODING option (patch by Martijn
Boerwinkel )
Version 7.10.6
--------------
2003-07-29 Markus F.X.J. Oberhumer
* Started working on support for CURLOPT_SSL_CTX_FUNCTION and
CURLOPT_SSL_CTX_DATA (libcurl-7.10.6) - not yet finished.
2003-06-10 Markus F.X.J. Oberhumer
* Added support for CURLOPT_HTTPAUTH (libcurl-7.10.6), including
the new HTTPAUTH_BASIC, HTTPAUTH_DIGEST, HTTPAUTH_GSSNEGOTIATE
and HTTPAUTH_NTML constants.
* Some constants were renamed for consistency:
All curl_infotype constants are now prefixed with "INFOTYPE_",
all curl_proxytype constants are prefixed with "PROXYTYPE_" instead
of "PROXY_", and all curl_TimeCond constants are now prefixed
with "TIMECONDITION_" instead of "TIMECOND_".
(The old names are still available but will get removed
in a future release.)
* WARNING: Removed the deprecated pycurl.init() and pycurl.multi_init()
names - use pycurl.Curl() and pycurl.CurlMulti() instead.
* WARNING: Removed the deprecated Curl.cleanup() and
CurlMulti.cleanup() methods - use Curl.close() and
CurlMulti.close() instead.
Version 7.10.5
--------------
2003-05-15 Markus F.X.J. Oberhumer
* Added support for CURLOPT_FTP_USE_EPRT (libcurl-7.10.5).
* Documentation updates.
2003-05-07 Eric S. Raymond
* Lifted all HTML docs to clean XHTML, verified by tidy.
2003-05-02 Markus F.X.J. Oberhumer
* Fixed some `int' vs. `long' mismatches that affected 64-bit systems.
* Fixed wrong pycurl.CAPATH constant.
2003-05-01 Markus F.X.J. Oberhumer
* Added new method Curl.errstr() which returns the internal
libcurl error buffer string of the handle.
Version 7.10.4.2
----------------
2003-04-15 Markus F.X.J. Oberhumer
* Allow compilation against the libcurl-7.10.3 release - some
recent Linux distributions (e.g. Mandrake 9.1) ship with 7.10.3,
and apart from the new CURLOPT_UNRESTRICTED_AUTH option there is
no need that we require libcurl-7.10.4.
Version 7.10.4
--------------
2003-04-01 Kjetil Jacobsen
* Markus added CURLOPT_UNRESTRICTED_AUTH (libcurl-7.10.4).
2003-02-25 Kjetil Jacobsen
* Fixed some broken test code and removed the fileupload test
since it didn't work properly.
2003-01-28 Kjetil Jacobsen
* Some documentation updates by Markus and me.
2003-01-22 Kjetil Jacobsen
* API CHANGE: the CurlMulti.info_read() method now returns
a separate array with handles that failed. Each entry in this array
is a tuple with (curl object, error number, error message).
This addition makes it simpler to do error checking of individual
curl objects when using the multi interface.
Version 7.10.3
--------------
2003-01-13 Kjetil Jacobsen
* PycURL memory usage has been reduced.
2003-01-10 Kjetil Jacobsen
* Added 'examples/retriever-multi.py' which shows how to retrieve
a set of URLs concurrently using the multi interface.
2003-01-09 Kjetil Jacobsen
* Added support for CURLOPT_HTTP200ALIASES.
2002-11-22 Kjetil Jacobsen
* Updated pycurl documentation in the 'doc' directory.
2002-11-21 Kjetil Jacobsen
* Updated and improved 'examples/curl.py'.
* Added 'tests/test_multi6.py' which shows how to use the
info_read method with CurlMulti.
2002-11-19 Kjetil Jacobsen
* Added new method CurlMulti.info_read().
Version 7.10.2
--------------
2002-11-14 Kjetil Jacobsen
* Free options set with setopt after cleanup is called, as cleanup
assumes that options are still valid when invoked. This fixes the
bug with COOKIEJAR reported by Bastiaan Naber
.
2002-11-06 Markus F.X.J. Oberhumer
* Install documentation under /usr/share/doc instead of /usr/doc.
Also, start shipping the (unfinished) HTML docs and some
basic test scripts.
2002-10-30 Markus F.X.J. Oberhumer
* API CHANGE: For integral values, Curl.getinfo() now returns a
Python-int instead of a Python-long.
Version 7.10.1
--------------
2002-10-03 Markus F.X.J. Oberhumer
* Added new module-level function version_info() from
libcurl-7.10.
Version 7.10
------------
2002-09-13 Kjetil Jacobsen
* Added commandline options to setup.py for specifying the path to
'curl-config' (non-windows) and the curl installation directory
(windows). See the 'INSTALL' file for details.
* Added CURLOPT_ENCODING, CURLOPT_NOSIGNAL and CURLOPT_BUFFERSIZE
from libcurl-7.10 (by Markus Oberhumer).
Version 7.9.8.4
---------------
2002-08-28 Kjetil Jacobsen
* Added a simple web-browser example based on gtkhtml and pycurl.
See the file 'examples/gtkhtml_demo.py' for details. The example
requires a working installation of gnome-python with gtkhtml
bindings enabled (pass --with-gtkhtml to gnome-python configure).
2002-08-14 Kjetil Jacobsen
* Added new method 'select' on CurlMulti objects. Example usage
in 'tests/test_multi5.py'. This method is just an optimization of
the combined use of fdset and select.
2002-08-12 Kjetil Jacobsen
* Added support for curl_multi_fdset. See the file
'tests/test_multi4.py' for example usage. Contributed by Conrad
Steenberg .
* perform() on multi objects now returns a tuple (result, number
of handles) like the libcurl interface does.
2002-08-08 Kjetil Jacobsen
* Added the 'sfquery' script which retrieves a SourceForge XML
export object for a given project. See the file 'examples/sfquery.py'
for details and usage. 'sfquery' was contributed by Eric
S. Raymond .
2002-07-20 Markus F.X.J. Oberhumer
* API enhancements: added Curl() and CurlMulti() as aliases for
init() and multi_init(), and added close() methods as aliases
for the cleanup() methods. The new names much better match
the actual intended use of the objects, and they also nicely
correspond to Python's file object.
* Also, all constants for Curl.setopt() and Curl.getinfo() are now
visible from within Curl objects.
All changes are fully backward-compatible.
Version 7.9.8.3
---------------
2002-07-16 Markus F.X.J. Oberhumer
* Under Python 2.2 or better, Curl and CurlMulti objects now
automatically participate in cyclic garbarge collection
(using the gc module).
Version 7.9.8.2
---------------
2002-07-05 Markus F.X.J. Oberhumer
* Curl and CurlMulti objects now support standard Python attributes.
See tests/test_multi2.py for an example.
2002-07-02 Kjetil Jacobsen
* Added support for the multi-interface.
Version 7.9.8.1
---------------
2002-06-25 Markus F.X.J. Oberhumer
* Fixed a couple of `int' vs. `size_t' mismatches in callbacks
and Py_BuildValue() calls.
2002-06-25 Kjetil Jacobsen
* Use 'double' type instead of 'size_t' for progress callbacks
(by Conrad Steenberg ). Also cleaned up
some other type mismatches in the callback interfaces.
2002-06-24 Kjetil Jacobsen
* Added example code on how to upload a file using HTTPPOST in
pycurl (code by Amit Mongia ). See the
file 'test_fileupload.py' for details.
Version 7.9.8
-------------
2002-06-24 Kjetil Jacobsen
* Resolved some build problems on Windows (by Markus Oberhumer).
2002-06-19 Kjetil Jacobsen
* Added CURLOPT_CAPATH.
* Added option constants for CURLOPT_NETRC: CURL_NETRC_OPTIONAL,
CURL_NETRC_IGNORED and CURL_NETRC_REQUIRED.
* Added option constants for CURLOPT_TIMECONDITION:
TIMECOND_IFMODSINCE and TIMECOND_IFUNMODSINCE.
* Added an simple example crawler, which downloads documents
listed in a file with a configurable number of worker threads.
See the file 'crawler.py' in the 'tests' directory for details.
* Removed the redundant 'test_xmlrpc2.py' test script.
* Disallow recursive callback invocations (by Markus Oberhumer).
2002-06-18 Kjetil Jacobsen
* Made some changes to setup.py which should fix the build
problems on RedHat 7.3 (suggested by Benji ).
* Use CURLOPT_READDATA instead of CURLOPT_INFILE, and
CURLOPT_WRITEDATA instead of CURLOPT_FILE. Also fixed some
reference counting bugs with file objects.
* CURLOPT_FILETIME and CURLINFO_FILETIME had a namespace clash
which caused them not to work. Use OPT_FILETIME for setopt() and
INFO_FILETIME for getinfo(). See example usage in
'test_getinfo.py' for details.
Version 7.9.7
-------------
2002-05-20 Kjetil Jacobsen
* New versioning scheme. Pycurl now has the same version number
as the libcurl version it was built with. The pycurl version
number thus indicates which version of libcurl is required to run.
2002-05-17 Kjetil Jacobsen
* Added CURLINFO_REDIRECT_TIME and CURLINFO_REDIRECT_COUNT.
2002-04-27 Kjetil Jacobsen
* Fixed potential memory leak and thread race (by Markus
Oberhumer).
Version 0.4.9
-------------
2002-04-15 Kjetil Jacobsen
* Added CURLOPT_DEBUGFUNCTION to allow debug callbacks to be
specified (see the file 'test_debug.py' for details on how to use
debug callbacks).
* Added CURLOPT_DNS_USE_GLOBAL_CACHE and
CURLOPT_DNS_CACHE_TIMEOUT.
* Fixed a segfault when finalizing curl objects in Python 1.5.2.
* Now requires libcurl 7.9.6 or greater.
2002-04-12 Kjetil Jacobsen
* Added 'test_post2.py' file which is another example on how to
issue POST requests.
2002-04-11 Markus F.X.J. Oberhumer
* Added the 'test_post.py' file which demonstrates the use of
POST requests.
Version 0.4.8
-------------
2002-03-07 Kjetil Jacobsen
* Added CURLOPT_PREQUOTE.
* Now requires libcurl 7.9.5 or greater.
* Other minor code cleanups and bugfixes.
2002-03-05 Kjetil Jacobsen
* Do not allow WRITEFUNCTION and WRITEHEADER on the same handle.
Version 0.4.7
-------------
2002-02-27 Kjetil Jacobsen
* Abort callback if the thread state of the calling thread cannot
be determined.
* Check that the installed version of libcurl matches the
requirements of pycurl.
2002-02-26 Kjetil Jacobsen
* Clarence Garnder found a bug where string
arguments to setopt sometimes were prematurely deallocated, this
should now be fixed.
2002-02-21 Kjetil Jacobsen
* Added the 'xmlrpc_curl.py' file which implements a transport
for xmlrpclib (xmlrpclib is part of Python 2.2).
* Added CURLINFO_CONTENT_TYPE.
* Added CURLOPT_SSLCERTTYPE, CURLOPT_SSLKEY, CURLOPT_SSLKEYTYPE,
CURLOPT_SSLKEYPASSWD, CURLOPT_SSLENGINE and
CURLOPT_SSLENGINE_DEFAULT.
* When thrown, the pycurl.error exception is now a tuple consisting
of the curl error code and the error message.
* Now requires libcurl 7.9.4 or greater.
2002-02-19 Kjetil Jacobsen
* Fixed docstring for getopt() function.
2001-12-18 Kjetil Jacobsen
* Updated the INSTALL information for Win32.
2001-12-12 Kjetil Jacobsen
* Added missing link flag to make pycurl build on MacOS X (by Matt
King ).
2001-12-06 Kjetil Jacobsen
* Added CURLINFO_STARTTRANSFER_TIME and CURLOPT_FTP_USE_EPSV from
libcurl 7.9.2.
2001-12-01 Markus F.X.J. Oberhumer
* Added the 'test_stringio.py' file which demonstrates the use of
StringIO objects as callback.
2001-12-01 Markus F.X.J. Oberhumer
* setup.py: Do not remove entries from a list while iterating
over it.
2001-11-29 Kjetil Jacobsen
* Added code in setup.py to install on Windows. Requires some
manual configuration (by Tino Lange ).
2001-11-27 Kjetil Jacobsen
* Improved detection of where libcurl is installed in setup.py.
Should make it easier to install pycurl when libcurl is not
located in regular lib/include paths.
2001-11-05 Kjetil Jacobsen
* Some of the newer options to setopt were missing, this should
now be fixed.
2001-11-04 Kjetil Jacobsen
* Exception handling has been improved and should no longer throw
spurious exceptions (by Markus F.X.J. Oberhumer
).
2001-10-15 Kjetil Jacobsen
* Refactored the test_gtk.py script to avoid global variables.
2001-10-12 Kjetil Jacobsen
* Added module docstrings, terse perhaps, but better than nothing.
* Added the 'basicfirst.py' file which is a Python version of the
corresponding Perl script by Daniel.
* PycURL now works properly under Python 1.5 and 1.6 (by Markus
F.X.J. Oberhumer ).
* Allow C-functions and Python methods as callbacks (by Markus
F.X.J. Oberhumer ).
* Allow None as success result of write, header and progress
callback invocations (by Markus F.X.J. Oberhumer
).
* Added the 'basicfirst2.py' file which demonstrates the use of a
class method as callback instead of just a function.
2001-08-21 Kjetil Jacobsen
* Cleaned up the script with GNOME/PycURL integration.
2001-08-20 Kjetil Jacobsen
* Added another test script for shipping XML-RPC requests which
uses py-xmlrpc to encode the arguments (tests/test_xmlrpc2.py).
2001-08-20 Kjetil Jacobsen
* Added test script for using PycURL and GNOME (tests/test_gtk.py).
2001-08-20 Kjetil Jacobsen
* Added test script for using XML-RPC (tests/test_xmlrpc.py).
* Added more comments to the test sources.
2001-08-06 Kjetil Jacobsen
* Renamed module namespace to pycurl instead of curl.
2001-08-06 Kjetil Jacobsen
* Set CURLOPT_VERBOSE to 0 by default.
2001-06-29 Kjetil Jacobsen
* Updated INSTALL, curl version 7.8 or greater is now mandatory to
use pycurl.
2001-06-13 Kjetil Jacobsen
* Set NOPROGRESS to 1 by default.
2001-06-07 Kjetil Jacobsen
* Added global_init/cleanup.
2001-06-06 Kjetil Jacobsen
* Added HEADER/PROGRESSFUNCTION callbacks (see files in tests/).
* Added PASSWDFUNCTION callback (untested).
* Added READFUNCTION callback (untested).
2001-06-05 Kjetil Jacobsen
* WRITEFUNCTION callbacks now work (see tests/test_cb.py for details).
* Preliminary distutils installation.
* Added CLOSEPOLICY constants to module namespace.
2001-06-04 Kjetil Jacobsen
* Return -1 on error from Python callback in WRITEFUNCTION callback.
2001-06-01 Kjetil Jacobsen
* Moved source to src and tests to tests directory.
2001-05-31 Kjetil Jacobsen
* Added better type checking for setopt.
2001-05-30 Kjetil Jacobsen
* Moved code to sourceforge.
* Added getinfo support.
# vi:ts=8:et
pycurl-7.43.0.2/pycurl.egg-info/ 0000755 0001750 0001750 00000000000 13304422066 015317 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/pycurl.egg-info/top_level.txt 0000644 0001750 0001750 00000000014 13304422066 020044 0 ustar me me 0000000 0000000 curl
pycurl
pycurl-7.43.0.2/pycurl.egg-info/PKG-INFO 0000644 0001750 0001750 00000011202 13304422066 016410 0 ustar me me 0000000 0000000 Metadata-Version: 1.1
Name: pycurl
Version: 7.43.0.2
Summary: PycURL -- A Python Interface To The cURL library
Home-page: http://pycurl.io/
Author: Oleg Pudeyev
Author-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 2.7 or 3.4 through 3.6.
- libcurl 7.19.0 or better.
Installation
------------
Download source and binary distributions from `PyPI`_ or `Bintray`_.
Binary wheels are now available for 32 and 64 bit Windows versions.
Please see `the installation documentation`_ for installation instructions.
.. _PyPI: https://pypi.python.org/pypi/pycurl
.. _Bintray: https://dl.bintray.com/pycurl/pycurl/
.. _the installation documentation: http://pycurl.io/docs/latest/install.html
Documentation
-------------
Documentation for the most recent PycURL release is available on
`PycURL website `_.
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
Classifier: Environment :: Web Environment
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Operating System :: POSIX
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.4
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Topic :: Internet :: File Transfer Protocol (FTP)
Classifier: Topic :: Internet :: WWW/HTTP
pycurl-7.43.0.2/pycurl.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 13304422066 021365 0 ustar me me 0000000 0000000
pycurl-7.43.0.2/pycurl.egg-info/SOURCES.txt 0000644 0001750 0001750 00000013204 13304422066 017203 0 ustar me me 0000000 0000000 AUTHORS
COPYING-LGPL
COPYING-MIT
ChangeLog
INSTALL.rst
MANIFEST.in
Makefile
README.rst
RELEASE-NOTES.rst
requirements-dev.txt
setup.py
winbuild.py
doc/callbacks.rst
doc/conf.py
doc/curl.rst
doc/curlmultiobject.rst
doc/curlobject.rst
doc/curlshareobject.rst
doc/files.rst
doc/index.rst
doc/install.rst
doc/internals.rst
doc/pycurl.rst
doc/quickstart.rst
doc/release-notes.rst
doc/release-process.rst
doc/thread-safety.rst
doc/troubleshooting.rst
doc/unicode.rst
doc/unimplemented.rst
doc/docstrings/curl.rst
doc/docstrings/curl_close.rst
doc/docstrings/curl_errstr.rst
doc/docstrings/curl_errstr_raw.rst
doc/docstrings/curl_getinfo.rst
doc/docstrings/curl_getinfo_raw.rst
doc/docstrings/curl_pause.rst
doc/docstrings/curl_perform.rst
doc/docstrings/curl_perform_rb.rst
doc/docstrings/curl_perform_rs.rst
doc/docstrings/curl_reset.rst
doc/docstrings/curl_set_ca_certs.rst
doc/docstrings/curl_setopt.rst
doc/docstrings/curl_setopt_string.rst
doc/docstrings/curl_unsetopt.rst
doc/docstrings/multi.rst
doc/docstrings/multi_add_handle.rst
doc/docstrings/multi_assign.rst
doc/docstrings/multi_close.rst
doc/docstrings/multi_fdset.rst
doc/docstrings/multi_info_read.rst
doc/docstrings/multi_perform.rst
doc/docstrings/multi_remove_handle.rst
doc/docstrings/multi_select.rst
doc/docstrings/multi_setopt.rst
doc/docstrings/multi_socket_action.rst
doc/docstrings/multi_socket_all.rst
doc/docstrings/multi_timeout.rst
doc/docstrings/pycurl_global_cleanup.rst
doc/docstrings/pycurl_global_init.rst
doc/docstrings/pycurl_module.rst
doc/docstrings/pycurl_version_info.rst
doc/docstrings/share.rst
doc/docstrings/share_close.rst
doc/docstrings/share_setopt.rst
doc/static/favicon.ico
examples/basicfirst.py
examples/file_upload.py
examples/linksys.py
examples/opensocketexception.py
examples/retriever-multi.py
examples/retriever.py
examples/sfquery.py
examples/smtp.py
examples/ssh_keyfunction.py
examples/xmlrpc_curl.py
examples/quickstart/file_upload_buffer.py
examples/quickstart/file_upload_real.py
examples/quickstart/file_upload_real_fancy.py
examples/quickstart/follow_redirect.py
examples/quickstart/form_post.py
examples/quickstart/get.py
examples/quickstart/get_python2.py
examples/quickstart/get_python2_https.py
examples/quickstart/get_python3.py
examples/quickstart/get_python3_https.py
examples/quickstart/put_buffer.py
examples/quickstart/put_file.py
examples/quickstart/response_headers.py
examples/quickstart/response_info.py
examples/quickstart/write_file.py
examples/tests/test_build_config.py
examples/tests/test_gtk.py
examples/tests/test_xmlrpc.py
pycurl.egg-info/PKG-INFO
pycurl.egg-info/SOURCES.txt
pycurl.egg-info/dependency_links.txt
pycurl.egg-info/top_level.txt
python/curl/__init__.py
src/docstrings.c
src/docstrings.h
src/easy.c
src/easycb.c
src/easyinfo.c
src/easyopt.c
src/easyperform.c
src/module.c
src/multi.c
src/oscompat.c
src/pycurl.h
src/pythoncompat.c
src/share.c
src/stringcompat.c
src/threadsupport.c
src/util.c
tests/__init__.py
tests/app.py
tests/appmanager.py
tests/cadata_test.py
tests/certinfo_test.py
tests/close_socket_cb_test.py
tests/curl_object_test.py
tests/debug_test.py
tests/default_write_cb_test.py
tests/error_constants_test.py
tests/error_test.py
tests/failonerror_test.py
tests/ftp_test.py
tests/getinfo_test.py
tests/global_init_test.py
tests/header_cb_test.py
tests/header_test.py
tests/high_level_curl_test.py
tests/info_constants_test.py
tests/internals_test.py
tests/matrix.py
tests/memory_mgmt_test.py
tests/multi_memory_mgmt_test.py
tests/multi_option_constants_test.py
tests/multi_socket_select_test.py
tests/multi_socket_test.py
tests/multi_test.py
tests/multi_timer_test.py
tests/open_socket_cb_test.py
tests/option_constants_test.py
tests/pause_test.py
tests/perform_test.py
tests/post_test.py
tests/procmgr.py
tests/protocol_constants_test.py
tests/read_cb_test.py
tests/readdata_test.py
tests/relative_url_test.py
tests/reload_test.py
tests/reset_test.py
tests/resolve_test.py
tests/run-quickstart.sh
tests/run.sh
tests/runwsgi.py
tests/seek_cb_constants_test.py
tests/seek_cb_test.py
tests/setopt_lifecycle_test.py
tests/setopt_string_test.py
tests/setopt_test.py
tests/setopt_unicode_test.py
tests/setup_test.py
tests/share_test.py
tests/sockopt_cb_test.py
tests/ssh_key_cb_test.py
tests/unset_range_test.py
tests/user_agent_string_test.py
tests/util.py
tests/version_comparison_test.py
tests/version_constants_test.py
tests/version_test.py
tests/vsftpd.conf
tests/weakref_test.py
tests/write_abort_test.py
tests/write_cb_bogus_test.py
tests/write_test.py
tests/write_to_stringio_test.py
tests/xferinfo_cb_test.py
tests/certs/ca.crt
tests/certs/ca.key
tests/certs/server.crt
tests/certs/server.key
tests/ext/test-lib.sh
tests/ext/test-suite.sh
tests/fake-curl/curl-config-empty
tests/fake-curl/curl-config-libs-and-static-libs
tests/fake-curl/curl-config-ssl-feature-only
tests/fake-curl/curl-config-ssl-in-libs
tests/fake-curl/curl-config-ssl-in-static-libs
tests/fake-curl/libcurl/Makefile
tests/fake-curl/libcurl/with_gnutls.c
tests/fake-curl/libcurl/with_gnutls.so
tests/fake-curl/libcurl/with_nss.c
tests/fake-curl/libcurl/with_nss.so
tests/fake-curl/libcurl/with_openssl.c
tests/fake-curl/libcurl/with_openssl.so
tests/fake-curl/libcurl/with_unknown_ssl.c
tests/fake-curl/libcurl/with_unknown_ssl.so
tests/fake-curl/libcurl/without_ssl.c
tests/fake-curl/libcurl/without_ssl.so
tests/fixtures/form_submission.txt
tests/matrix/curl-7.19.0-sslv2-2b0e09b0f98.patch
tests/matrix/curl-7.19.0-sslv2-c66b0b32fba-modified.patch
tests/matrix/openssl-1.0.1e-fix_pod_syntax-1.patch
winbuild/c-ares-vs2015.patch
winbuild/libcurl-fix-zlib-references.patch
winbuild/libssh2-vs2015.patch
winbuild/openssl-fix-crt-1.0.2.patch
winbuild/openssl-fix-crt-1.1.0.patch
winbuild/vcvars-vc14-32.sh
winbuild/vcvars-vc14-64.sh pycurl-7.43.0.2/RELEASE-NOTES.rst 0000644 0001750 0001750 00000013724 13304422026 015012 0 ustar me me 0000000 0000000 Release Notes
=============
PycURL 7.43.0.2 - 2018-06-02
----------------------------
Highlights of this release:
1. Experimental perform_rs and perform_rb methods have been added to Curl
objects. They return response body as a string and a byte string,
respectively. The goal of these methods is to improve PycURL's usability
for typical use cases, specifically removing the need to set up
StringIO/BytesIO objects to store the response body.
2. getinfo_raw and errstr_raw methods have been added to Curl objects to
return transfer information as byte strings, permitting applications to
retrieve transfer information that is not decodable using Python's
default encoding.
3. errstr and "fail or error" exceptions now replace undecodable bytes
so as to provide usable strings; use errstr_raw to retrieve original
byte strings.
4. There is no longer a need to keep references to Curl objects when they
are used in CurlMulti objects - PycURL now maintains such references
internally.
5. Official Windows builds now include HTTP/2 and international domain
name support.
6. PycURL now officially supports BoringSSL.
7. A number of smaller improvements have been made and bugs fixed.
PycURL 7.43.0.1 - 2017-12-07
----------------------------
This release collects fixes and improvements made over the past two years,
notably updating Windows dependencies to address DNS resolution and
TLS connection issues.
PycURL 7.43.0 - 2016-02-02
--------------------------
Highlights of this release:
1. Binary wheels are now built for Windows systems.
2. setopt_string method added to Curl objects to permit setting string libcurl
options that PycURL does not know about.
3. curl module can now be imported on Windows again.
4. OPENSOCKETFUNCTION callback is now invoked with the address as bytes on
Python 3 as was documented.
5. Support for many libcurl options and constants was added.
PycURL 7.21.5 - 2016-01-05
--------------------------
Highlights of this release:
1. Socket callbacks are now fully implemented (``CURLOPT_OPENSOCKETFUNCTION``,
``CURLOPT_SOCKOPTFUNCTION``, ``CURLOPT_CLOSESOCKETFUNCTION``). Unfortunately
this required changing ``OPENSOCKETFUNCTION`` API once again in a
backwards-incompatible manner. Support for ``SOCKOPTFUNCTION`` and
``CLOSESOCKETFUNCTION`` was added in this release. ``OPENSOCKETFUNCTION``
now supports Unix sockets.
2. Many other libcurl options and constants have been added to PycURL.
3. When ``pycurl`` module initialization fails, ``ImportError`` is raised
instead of a fatal error terminating the process.
4. Usability of official Windows builds has been greatly improved:
* Dependencies are linked statically, eliminating possible DLL conflicts.
* OpenSSL is used instead of WinSSL.
* libcurl is linked against C-Ares and libssh2.
PycURL 7.19.5.3 - 2015-11-03
----------------------------
PycURL 7.19.5.2 release did not include some of the test suite files in
its manifest, leading to inability to run the test suite from the sdist
tarball. This is now fixed thanks to Kamil Dudka.
PycURL 7.19.5.2 - 2015-11-02
----------------------------
Breaking change: DEBUGFUNCTION now takes bytes rather than (Unicode) string
as its argument on Python 3.
Breaking change: CURLMOPT_* option constants moved from Easy to Multi
class. They remain available in pycurl module.
SSL library detection improved again, --libcurl-dll option to setup.py added.
Options that required tuples now also accept lists, and vice versa.
This release fixes several memory leaks and one use after free issue.
Support for several new libcurl options and constants has been added.
PycURL 7.19.5.1 - 2015-01-06
----------------------------
This release primarily fixes build breakage against libcurl 7.19.4 through
7.21.1, such as versions shipped with CentOS.
PycURL 7.19.5 - 2014-07-12
--------------------------
PycURL C code has been significantly reorganized. Curl, CurlMulti and
CurlShare classes are now properly exported, instead of factory functions for
the respective objects. PycURL API has not changed.
Documentation has been transitioned to Sphinx and reorganized as well.
Both docstrings and standalone documentation are now more informative.
Documentation is no longer included in released distributions. It can be
generated from source by running `make docs`.
Tests are no longer included in released distributions. Instead the
documentation and quickstart examples should be consulted for sample code.
Official Windows builds now are linked against zlib.
PycURL 7.19.3.1 - 2014-02-05
----------------------------
This release restores PycURL's ability to automatically detect SSL library
in use in most circumstances, thanks to Andjelko Horvat.
PycURL 7.19.3 - 2014-01-09
--------------------------
This release brings official Python 3 support to PycURL.
Several GNU/Linux distributions provided Python 3 packages of PycURL
previously; these packages were based on patches that were incomplete and
in some places incorrect. Behavior of PycURL 7.19.3 and later may therefore
differ from behavior of unofficial Python 3 packages of previous PycURL
versions.
To summarize the behavior under Python 3, PycURL will accept ``bytes`` where
it accepted strings under Python 2, and will also accept Unicode strings
containing ASCII codepoints only for convenience. Please refer to
`Unicode`_ and `file`_ documentation for further details.
In the interests of compatibility, PycURL will also accept Unicode data on
Python 2 given the same constraints as under Python 3.
While Unicode and file handling rules are expected to be sensible for
all use cases, and retain backwards compatibility with previous PycURL
versions, please treat behavior of this versions under Python 3 as experimental
and subject to change.
Another potentially disruptive change in PycURL is the requirement for
compile time and runtime SSL backends to match. Please see the readme for
how to indicate the SSL backend to setup.py.
.. _Unicode: doc/unicode.html
.. _file: doc/files.html
pycurl-7.43.0.2/winbuild/ 0000755 0001750 0001750 00000000000 13304422066 014124 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/winbuild/libssh2-vs2015.patch 0000644 0001750 0001750 00000000424 13211045147 017447 0 ustar me me 0000000 0000000 --- win32/libssh2_config.h.orig 2014-12-04 13:43:57.000000000 -0800
+++ win32/libssh2_config.h 2016-01-02 21:56:50.468363200 -0800
@@ -24,7 +24,6 @@
#define HAVE_SELECT
#ifdef _MSC_VER
-#define snprintf _snprintf
#if _MSC_VER < 1500
#define vsnprintf _vsnprintf
#endif
pycurl-7.43.0.2/winbuild/c-ares-vs2015.patch 0000644 0001750 0001750 00000000606 13211045147 017255 0 ustar me me 0000000 0000000 --- a/Makefile.msvc 2015-12-02 22:40:45
+++ b/Makefile.msvc 2015-12-02 22:46:39
@@ -125,6 +125,12 @@
CC_VERS_NUM = 110
!ELSEIF "$(_NMAKE_VER)" == "11.00.60315.1"
CC_VERS_NUM = 110
+!ELSEIF "$(_NMAKE_VER)" == "11.00.61030.0"
+CC_VERS_NUM = 110
+!ELSEIF "$(_NMAKE_VER)" == "12.00.21005.1"
+CC_VERS_NUM = 120
+!ELSEIF "$(_NMAKE_VER)" == "14.00.23026.0"
+CC_VERS_NUM = 140
!ELSE
pycurl-7.43.0.2/winbuild/vcvars-vc14-64.sh 0000644 0001750 0001750 00000001777 13303244032 016774 0 ustar me me 0000000 0000000 # Courtesy of libiconv 1.15
# Set environment variables for using MSVC 14,
# for creating native 64-bit Windows executables.
# Windows C library headers and libraries.
WindowsCrtIncludeDir='C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt'
WindowsCrtLibDir='C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\'
INCLUDE="${WindowsCrtIncludeDir};$INCLUDE"
LIB="${WindowsCrtLibDir}x64;$LIB"
# Windows API headers and libraries.
WindowsSdkIncludeDir='C:\Program Files (x86)\Windows Kits\8.1\Include\'
WindowsSdkLibDir='C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\'
INCLUDE="${WindowsSdkIncludeDir}um;${WindowsSdkIncludeDir}shared;$INCLUDE"
LIB="${WindowsSdkLibDir}x64;$LIB"
# Visual C++ tools, headers and libraries.
VSINSTALLDIR='C:\Program Files (x86)\Microsoft Visual Studio 14.0'
VCINSTALLDIR="${VSINSTALLDIR}"'\VC'
PATH=`cygpath -u "${VCINSTALLDIR}"`/bin/amd64:"$PATH"
INCLUDE="${VCINSTALLDIR}"'\include;'"${INCLUDE}"
LIB="${VCINSTALLDIR}"'\lib\amd64;'"${LIB}"
export INCLUDE LIB pycurl-7.43.0.2/winbuild/openssl-fix-crt-1.1.0.patch 0000644 0001750 0001750 00000003352 13211045165 020636 0 ustar me me 0000000 0000000 --- Configurations/10-main.conf.orig 2016-11-10 06:03:43.000000000 -0800
+++ Configurations/10-main.conf 2016-12-15 20:18:47.576426000 -0800
@@ -1291,7 +1291,7 @@
($disabled{shared} ? "" : "/MD")
." /O2";
})),
- lib_cflags => add(sub { $disabled{shared} ? "/MT /Zl" : () }),
+ lib_cflags => add(sub { $disabled{shared} ? "/MD" : () }),
# Following might/should appears controversial, i.e. defining
# /MDd without evaluating $disabled{shared}. It works in
# non-shared build because static library is compiled with /Zl
@@ -1304,7 +1304,7 @@
# prefer [non-debug] openssl.exe to be free from Micorosoft RTL
# redistributable.
bin_cflags => add(picker(debug => "/MDd",
- release => sub { $disabled{shared} ? "/MT" : () },
+ release => sub { $disabled{shared} ? "/MD" : () },
)),
bin_lflags => add("/subsystem:console /opt:ref"),
ex_libs => add(sub {
@@ -1385,7 +1385,7 @@
sub { defined($ENV{'PORTSDK_LIBPATH'})
? '-I$(PORTSDK_LIBPATH)/../../include' : (); },
sub { `cl 2>&1` =~ /Version ([0-9]+)\./ && $1>=14
- ? ($disabled{shared} ? " /MT" : " /MD")
+ ? ($disabled{shared} ? " /MD" : " /MD")
: " /MC"; }),
debug => "/Od -DDEBUG -D_DEBUG",
release => "/O1i"),
pycurl-7.43.0.2/winbuild/openssl-fix-crt-1.0.2.patch 0000644 0001750 0001750 00000002472 13211045165 020641 0 ustar me me 0000000 0000000 --- util/pl/VC-32.pl.orig 2015-12-03 06:04:23.000000000 -0800
+++ util/pl/VC-32.pl 2016-01-01 23:56:32.542632200 -0800
@@ -45,7 +45,7 @@
# considered safe to ignore.
#
$base_cflags= " $mf_cflag";
- my $f = $shlib || $fips ?' /MD':' /MT';
+ my $f = $shlib || $fips ?' /MD':' /MD';
$opt_cflags=$f.' /Ox';
$dbg_cflags=$f.'d /Od -DDEBUG -D_DEBUG';
$lflags="/nologo /subsystem:console /opt:ref";
@@ -119,7 +119,7 @@
$base_cflags.=' -I$(WCECOMPAT)/include' if (defined($ENV{'WCECOMPAT'}));
$base_cflags.=' -I$(PORTSDK_LIBPATH)/../../include' if (defined($ENV{'PORTSDK_LIBPATH'}));
if (`$cc 2>&1` =~ /Version ([0-9]+)\./ && $1>=14) {
- $base_cflags.=$shlib?' /MD':' /MT';
+ $base_cflags.=$shlib?' /MD':' /MD';
} else {
$base_cflags.=' /MC';
}
@@ -130,13 +130,13 @@
else # Win32
{
$base_cflags= " $mf_cflag";
- my $f = $shlib || $fips ?' /MD':' /MT';
+ my $f = $shlib || $fips ?' /MD':' /MD';
$ff = "/fixed";
$opt_cflags=$f.' /Ox /O2 /Ob2';
$dbg_cflags=$f.'d /Od -DDEBUG -D_DEBUG';
$lflags="/nologo /subsystem:console /opt:ref";
}
-$lib_cflag='/Zl' if (!$shlib); # remove /DEFAULTLIBs from static lib
+#$lib_cflag='/Zl' if (!$shlib); # remove /DEFAULTLIBs from static lib
$mlflags='';
$out_def ="out32"; $out_def.="dll" if ($shlib);
pycurl-7.43.0.2/winbuild/libcurl-fix-zlib-references.patch 0000644 0001750 0001750 00000000437 13303127222 022441 0 ustar me me 0000000 0000000 --- winbuild/MakefileBuild.vc.orig 2015-11-27 07:00:14.000000000 -0800
+++ winbuild/MakefileBuild.vc 2016-01-01 21:33:44.263840800 -0800
@@ -238,7 +238,7 @@
# Runtime library configuration
!IF "$(RTLIBCFG)"=="static"
-RTLIB = /MT
+RTLIB = /MD
RTLIB_DEBUG = /MTd
!ELSE
RTLIB = /MD
pycurl-7.43.0.2/winbuild/vcvars-vc14-32.sh 0000644 0001750 0001750 00000001763 13303244032 016762 0 ustar me me 0000000 0000000 # Courtesy of libiconv 1.15
# Set environment variables for using MSVC 14,
# for creating native 32-bit Windows executables.
# Windows C library headers and libraries.
WindowsCrtIncludeDir='C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt'
WindowsCrtLibDir='C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\'
INCLUDE="${WindowsCrtIncludeDir};$INCLUDE"
LIB="${WindowsCrtLibDir}x86;$LIB"
# Windows API headers and libraries.
WindowsSdkIncludeDir='C:\Program Files (x86)\Windows Kits\8.1\Include\'
WindowsSdkLibDir='C:\Program Files (x86)\Windows Kits\8.1\Lib\winv6.3\um\'
INCLUDE="${WindowsSdkIncludeDir}um;${WindowsSdkIncludeDir}shared;$INCLUDE"
LIB="${WindowsSdkLibDir}x86;$LIB"
# Visual C++ tools, headers and libraries.
VSINSTALLDIR='C:\Program Files (x86)\Microsoft Visual Studio 14.0'
VCINSTALLDIR="${VSINSTALLDIR}"'\VC'
PATH=`cygpath -u "${VCINSTALLDIR}"`/bin:"$PATH"
INCLUDE="${VCINSTALLDIR}"'\include;'"${INCLUDE}"
LIB="${VCINSTALLDIR}"'\lib;'"${LIB}"
export INCLUDE LIB
pycurl-7.43.0.2/INSTALL.rst 0000644 0001750 0001750 00000030524 13277627465 014176 0 ustar me me 0000000 0000000 .. _install:
PycURL Installation
===================
NOTE: You need Python and libcurl installed on your system to use or
build pycurl. Some RPM distributions of curl/libcurl do not include
everything necessary to build pycurl, in which case you need to
install the developer specific RPM which is usually called curl-dev.
Distutils
---------
Build and install pycurl with the following commands::
(if necessary, become root)
tar -zxvf pycurl-$VER.tar.gz
cd pycurl-$VER
python setup.py install
$VER should be substituted with the pycurl version number, e.g. 7.10.5.
Note that the installation script assumes that 'curl-config' can be
located in your path setting. If curl-config is installed outside
your path or you want to force installation to use a particular
version of curl-config, use the '--curl-config' command line option to
specify the location of curl-config. Example::
python setup.py install --curl-config=/usr/local/bin/curl-config
If libcurl is linked dynamically with pycurl, you may have to alter the
LD_LIBRARY_PATH environment variable accordingly. This normally
applies only if there is more than one version of libcurl installed,
e.g. one in /usr/lib and one in /usr/local/lib.
SSL
^^^
PycURL requires that the SSL library that it is built against is the same
one libcurl, and therefore PycURL, uses at runtime. PycURL's ``setup.py``
uses ``curl-config`` to attempt to figure out which SSL library libcurl
was compiled against, however this does not always work. If PycURL is unable
to determine the SSL library in use it will print a warning similar to
the following::
src/pycurl.c:137:4: warning: #warning "libcurl was compiled with SSL support, but configure could not determine which " "library was used; thus no SSL crypto locking callbacks will be set, which may " "cause random crashes on SSL requests" [-Wcpp]
It will then fail at runtime as follows::
ImportError: pycurl: libcurl link-time ssl backend (openssl) is different from compile-time ssl backend (none/other)
To fix this, you need to tell ``setup.py`` what SSL backend is used::
python setup.py --with-[openssl|gnutls|nss] install
Note: as of PycURL 7.21.5, setup.py accepts ``--with-openssl`` option to
indicate that libcurl is built against OpenSSL. ``--with-ssl`` is an alias
for ``--with-openssl`` and continues to be accepted for backwards compatibility.
You can also ask ``setup.py`` to obtain SSL backend information from installed
libcurl shared library, as follows:
python setup.py --libcurl-dll=libcurl.so
An unqualified ``libcurl.so`` would use the system libcurl, or you can
specify a full path.
easy_install / pip
------------------
::
easy_install pycurl
pip install pycurl
If you need to specify an alternate curl-config, it can be done via an
environment variable::
export PYCURL_CURL_CONFIG=/usr/local/bin/curl-config
easy_install pycurl
The same applies to the SSL backend, if you need to specify it (see the SSL
note above)::
export PYCURL_SSL_LIBRARY=[openssl|gnutls|nss]
easy_install pycurl
pip and cached pycurl package
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have already installed pycurl and are trying to reinstall it via
pip with different SSL options for example, pip may reinstall the package it
has previously compiled instead of recompiling pycurl with newly specified
options. More details are given in `this Stack Overflow post`_.
To force pip to recompile pycurl, run::
# upgrade pip if necessary
pip install --upgrade pip
# remove current pycurl
pip uninstall pycurl
# set PYCURL_SSL_LIBRARY
export PYCURL_SSL_LIBRARY=nss
# recompile and install pycurl
pip install --compile pycurl
.. _this Stack Overflow post: http://stackoverflow.com/questions/21487278/ssl-error-installing-pycurl-after-ssl-is-set
Windows
-------
Official Packages
^^^^^^^^^^^^^^^^^
As of version 7.43.0, PycURL provides binary wheels for Windows. If you are
using an official distribution of Python (i.e., one downloaded from
https://www.python.org/), and you are using pip, you should be able to
install PycURL by running:
pip install pycurl
If you are not using pip, EXE and MSI installers are available in the
`download area`_.
Both 32-bit and 64-bit builds of PycURL are available for Windows.
Using PycURL With Custom Python Builds
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
As of version 7.21.5, PycURL is linked statically against all of its
dependencies except MSVCRT. This means that as long as your custom Python
build uses the same version of MSVC as the corresponding official Python build
as well as the same MSVCRT linking setting (/MD et. al.) you should be
able to use an official PycURL package.
If your Python build uses different MSVCRT settings or a different MSVC
version from the official Python builds, you will need to compile PycURL
from source.
Currently official PycURL packages are built against the following Python
versions:
- 2.7.10
- 3.2.5
- 3.3.5
- 3.4.3
- 3.5.2
- 3.6.0
If the C runtime library (MSVCRT.DLL) versions used by PycURL and Python
do not match, you will receive a message
like the following one when trying to import ``pycurl`` module::
ImportError: DLL load failed: The specified procedure could not be found.
To identify which MSVCRT version your Python uses use the
`application profiling feature`_ of
`Dependency Walker`_ and look for `msvcrt.dll variants`_ being loaded.
You may find `the entire thread starting here`_ helpful.
.. _application profiling feature: https://curl.haxx.se/mail/curlpython-2014-05/0007.html
.. _Dependency Walker: http://www.dependencywalker.com/
.. _msvcrt.dll variants: https://curl.haxx.se/mail/curlpython-2014-05/0010.html
.. _the entire thread starting here: https://curl.haxx.se/mail/curlpython-2014-05/0000.html
Building From Source
^^^^^^^^^^^^^^^^^^^^
Building PycURL from source is not for the faint of heart due to the multitude
of possible dependencies and each of these dependencies having its own
directory structure, configuration style, parameters and quirks.
Additionally different dependencies have different
settings for MSVCRT usage, and an application must have all of its parts
agreeing on a single setting. If you decide to build PycURL from source
it is advisable to look through the ``winbuild.py``
script - it is used to build the official binaries and contains a wealth
of information for compiling PycURL's dependencies on Windows.
If you are compiling PycURL from source it is recommended to compile all of its
dependencies from source as well. Using precompiled libraries may lead to
multiple MSVCRT versions mixed in the resulting PycURL binary, which will
not be good.
If PycURL is to be linked statically against its dependencies, OpenSSL must
be patched to link to the DLL version of MSVCRT. There is a patch for this in
``winbuild`` directory of PycURL source.
For a minimum build you will just need libcurl source. Follow its Windows
build instructions to build either a static or a DLL version of the library,
then configure PycURL as follows to use it::
python setup.py --curl-dir=c:\dev\curl-7.33.0\builds\libcurl-vc-x86-release-dll-ipv6-sspi-spnego-winssl --use-libcurl-dll
Note that ``--curl-dir`` must point not to libcurl source but rather to headers
and compiled libraries.
If libcurl and Python are not linked against the same exact C runtime
(version number, static/dll, single-threaded/multi-threaded) you must use
``--avoid-stdio`` option (see below).
Additional Windows setup.py options:
- ``--use-libcurl-dll``: build against libcurl DLL, if not given PycURL will
be built against libcurl statically.
- ``--libcurl-lib-name=libcurl_imp.lib``: specify a different name for libcurl
import library. The default is ``libcurl.lib`` which is appropriate for
static linking and is sometimes the correct choice for dynamic linking as
well. The other possibility for dynamic linking is ``libcurl_imp.lib``.
- ``--with-openssl``: use OpenSSL crypto locks when libcurl was built against
OpenSSL.
- ``--with-ssl``: legacy alias for ``--with-openssl``.
- ``--openssl-lib-name=""``: specify a different name for OpenSSL import
library containing CRYPTO_num_locks. For OpenSSL 1.1.0+ this should be set
to an empty string as given here.
- ``--avoid-stdio``: on Windows, a process and each library it is using
may be linked to its own version of the C runtime (MSVCRT).
FILE pointers from one C runtime may not be passed to another C runtime.
This option prevents direct passing of FILE pointers from Python to libcurl,
thus permitting Python and libcurl to be linked against different C runtimes.
This option may carry a performance penalty when Python file objects are
given directly to PycURL in CURLOPT_READDATA, CURLOPT_WRITEDATA or
CURLOPT_WRITEHEADER options. This option applies only on Python 2; on
Python 3, file objects no longer expose C library FILE pointers and the
C runtime issue does not exist. On Python 3, this option is recognized but
does nothing. You can also give ``--avoid-stdio`` option in
PYCURL_SETUP_OPTIONS environment variable as follows::
PYCURL_SETUP_OPTIONS=--avoid-stdio pip install pycurl
A good ``setup.py`` target to use is ``bdist_wininst`` which produces an
executable installer that you can run to install PycURL.
You may find the following mailing list posts helpful:
- https://curl.haxx.se/mail/curlpython-2009-11/0010.html
- https://curl.haxx.se/mail/curlpython-2013-11/0002.html
winbuild.py
^^^^^^^^^^^
This script is used to build official PycURL Windows packages. You can
use it to build a full complement of packages with your own options or modify
it to build a single package you need.
Prerequisites:
- `Git for Windows`_.
- Appropriate `Python versions`_ installed.
- MS Visual C++ 9/2008 for Python <= 3.2, MS Visual C++ 10/2010 for
Python 3.3 or 3.4, MS Visual C++ 14/2015 for Python 3.5 or 3.6.
Express versions of Visual Studio work fine for this,
although getting 64 bit compilers to wok in some Express versions involves
jumping through several hoops.
- NASM if building libcurl against OpenSSL.
- ActivePerl if building libcurl against OpenSSL. The perl shipping with
Git for Windows handles forward and backslashes in paths in a way that is
incompatible with OpenSSL's build scripts.
.. _Git for Windows: https://git-for-windows.github.io/
.. _Python versions: http://python.org/download/
``winbuild.py`` assumes all programs are installed in their default locations,
if this is not the case edit it as needed. ``winbuild.py`` itself can be run
with any Python it supports - 2.7 or 3.2 through 3.6.
.. _`download area`: https://dl.bintray.com/pycurl/pycurl/
Git Checkout
------------
In order to build PycURL from a Git checkout, some files need to be
generated. On Unix systems it is easiest to build PycURL with ``make``::
make
To specify which curl or SSL backend to compile against, use the same
environment variables as easy_install/pip, namely ``PYCURL_CURL_CONFIG``
and ``PYCURL_SSL_LIBRARY``.
To generate generated files only you may run::
make gen
This might be handy if you are on Windows. Remember to run ``make gen``
whenever you change sources.
To generate documentation, run::
make docs
Generating documentation requires `Sphinx`_ to be installed.
.. _Sphinx: http://sphinx-doc.org/
A Note Regarding SSL Backends
-----------------------------
libcurl's functionality varies depending on which SSL backend it is compiled
against. For example, users have `reported`_ `problems`_ with GnuTLS backend.
As of this writing, generally speaking, OpenSSL backend has the most
functionality as well as the best compatibility with other software.
If you experience SSL issues, especially if you are not using OpenSSL
backend, you can try rebuilding libcurl and PycURL against another SSL backend.
.. _reported: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=515200
.. _problems: https://bugs.launchpad.net/ubuntu/+source/pycurl/+bug/1111673
SSL Certificate Bundle
----------------------
libcurl, and PycURL, by default verify validity of HTTPS servers' SSL
certificates. Doing so requires a CA certificate bundle, which libcurl
and most SSL libraries do not provide.
Here_ is a good resource on how to build your own certificate bundle.
certifie.com also has a `prebuilt certificate bundle`_.
To use the certificate bundle, use ``CAINFO`` or ``CAPATH`` PycURL
options.
.. _Here: http://certifie.com/ca-bundle/
.. _prebuilt certificate bundle: http://certifie.com/ca-bundle/ca-bundle.crt.txt
pycurl-7.43.0.2/examples/ 0000755 0001750 0001750 00000000000 13304422066 014125 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/examples/smtp.py 0000644 0001750 0001750 00000002113 13304414701 015454 0 ustar me me 0000000 0000000 # Based on the simple libcurl SMTP example:
# https://github.com/bagder/curl/blob/master/docs/examples/smtp-mail.c
# There are other SMTP examples in that directory that you may find helpful.
from . import localhost
import pycurl
try:
from io import BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
import sys
PY3 = sys.version_info[0] > 2
mail_server = 'smtp://%s' % localhost
mail_from = 'sender@example.org'
mail_to = 'addressee@example.net'
c = pycurl.Curl()
c.setopt(c.URL, mail_server)
c.setopt(c.MAIL_FROM, mail_from)
c.setopt(c.MAIL_RCPT, [mail_to])
message = '''\
From: %s
To: %s
Subject: PycURL SMTP example
SMTP example via PycURL
''' % (mail_from, mail_to)
if PY3:
message = message.encode('ascii')
# libcurl does not perform buffering, therefore
# we need to wrap the message string into a BytesIO or StringIO.
io = BytesIO(message)
c.setopt(c.READDATA, io)
# If UPLOAD is not set, libcurl performs SMTP VRFY.
# Setting UPLOAD to True sends a message.
c.setopt(c.UPLOAD, True)
# Observe SMTP conversation.
c.setopt(c.VERBOSE, True)
c.perform()
pycurl-7.43.0.2/examples/file_upload.py 0000644 0001750 0001750 00000002233 13151540633 016763 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
import os, sys
import pycurl
# Class which holds a file reference and the read callback
class FileReader:
def __init__(self, fp):
self.fp = fp
def read_callback(self, size):
return self.fp.read(size)
# Check commandline arguments
if len(sys.argv) < 3:
print("Usage: %s " % sys.argv[0])
raise SystemExit
url = sys.argv[1]
filename = sys.argv[2]
if not os.path.exists(filename):
print("Error: the file '%s' does not exist" % filename)
raise SystemExit
# Initialize pycurl
c = pycurl.Curl()
c.setopt(pycurl.URL, url)
c.setopt(pycurl.UPLOAD, 1)
# Two versions with the same semantics here, but the filereader version
# is useful when you have to process the data which is read before returning
if 1:
c.setopt(pycurl.READFUNCTION, FileReader(open(filename, 'rb')).read_callback)
else:
c.setopt(pycurl.READFUNCTION, open(filename, 'rb').read)
# Set size of file to be uploaded.
filesize = os.path.getsize(filename)
c.setopt(pycurl.INFILESIZE, filesize)
# Start transfer
print('Uploading file %s to url %s' % (filename, url))
c.perform()
c.close()
pycurl-7.43.0.2/examples/retriever.py 0000644 0001750 0001750 00000005151 13211045165 016506 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
#
# Usage: python retriever.py [<# of
# concurrent connections>]
#
import sys, threading
try:
import Queue
except ImportError:
import queue as Queue
import pycurl
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
except ImportError:
pass
else:
signal.signal(SIGPIPE, SIG_IGN)
# Get args
num_conn = 10
try:
if sys.argv[1] == "-":
urls = sys.stdin.readlines()
else:
urls = open(sys.argv[1]).readlines()
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
print("Usage: %s [<# of concurrent connections>]" % sys.argv[0])
raise SystemExit
# Make a queue with (url, filename) tuples
queue = Queue.Queue()
for url in urls:
url = url.strip()
if not url or url[0] == "#":
continue
filename = "doc_%03d.dat" % (len(queue.queue) + 1)
queue.put((url, filename))
# Check args
assert queue.queue, "no URLs given"
num_urls = len(queue.queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
print("----- Getting", num_urls, "URLs using", num_conn, "connections -----")
class WorkerThread(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def run(self):
while 1:
try:
url, filename = self.queue.get_nowait()
except Queue.Empty:
raise SystemExit
fp = open(filename, "wb")
curl = pycurl.Curl()
curl.setopt(pycurl.URL, url)
curl.setopt(pycurl.FOLLOWLOCATION, 1)
curl.setopt(pycurl.MAXREDIRS, 5)
curl.setopt(pycurl.CONNECTTIMEOUT, 30)
curl.setopt(pycurl.TIMEOUT, 300)
curl.setopt(pycurl.NOSIGNAL, 1)
curl.setopt(pycurl.WRITEDATA, fp)
try:
curl.perform()
except:
import traceback
traceback.print_exc(file=sys.stderr)
sys.stderr.flush()
curl.close()
fp.close()
sys.stdout.write(".")
sys.stdout.flush()
# Start a bunch of threads
threads = []
for dummy in range(num_conn):
t = WorkerThread(queue)
t.start()
threads.append(t)
# Wait for all threads to finish
for thread in threads:
thread.join()
pycurl-7.43.0.2/examples/linksys.py 0000644 0001750 0001750 00000052413 13211045147 016176 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
#
# linksys.py -- program settings on a Linkys router
#
# This tool is designed to help you recover from the occasional episodes
# of catatonia that afflict Linksys boxes. It allows you to batch-program
# them rather than manually entering values to the Web interface. Commands
# are taken from the command line first, then standard input.
#
# The somewhat spotty coverage of status queries is because I only did the
# ones that were either (a) easy, or (b) necessary. If you want to know the
# status of the box, look at the web interface.
#
# This code has been tested against the following hardware:
#
# Hardware Firmware
# ---------- ---------------------
# BEFW11S4v2 1.44.2.1, Dec 20 2002
#
# The code is, of course, sensitive to changes in the names of CGI pages
# and field names.
#
# Note: to make the no-arguments form work, you'll need to have the following
# entry in your ~/.netrc file. If you have changed the router IP address or
# name/password, modify accordingly.
#
# machine 192.168.1.1
# login ""
# password admin
#
# By Eric S. Raymond, August April 2003. All rites reversed.
import sys, re, curl, exceptions
def print_stderr(arg):
sys.stderr.write(arg)
sys.stderr.write("\n")
class LinksysError(exceptions.Exception):
def __init__(self, *args):
self.args = args
class LinksysSession:
months = 'Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec'
WAN_CONNECT_AUTO = '1'
WAN_CONNECT_STATIC = '2'
WAN_CONNECT_PPOE = '3'
WAN_CONNECT_RAS = '4'
WAN_CONNECT_PPTP = '5'
WAN_CONNECT_HEARTBEAT = '6'
# Substrings to check for on each page load.
# This may enable us to detect when a firmware change has hosed us.
check_strings = {
"": "basic setup functions",
"Passwd.htm": "For security reasons,",
"DHCP.html": "You can configure the router to act as a DHCP",
"Log.html": "There are some log settings and lists in this page.",
"Forward.htm":"Port forwarding can be used to set up public services",
}
def __init__(self):
self.actions = []
self.host = "http://192.168.1.1"
self.verbosity = False
self.pagecache = {}
def set_verbosity(self, flag):
self.verbosity = flag
# This is not a performance hack -- we need the page cache to do
# sanity checks at configure time.
def cache_load(self, page):
if page not in self.pagecache:
fetch = curl.Curl(self.host)
fetch.set_verbosity(self.verbosity)
fetch.get(page)
self.pagecache[page] = fetch.body()
if fetch.answered("401"):
raise LinksysError("authorization failure.", True)
elif not fetch.answered(LinksysSession.check_strings[page]):
del self.pagecache[page]
raise LinksysError("check string for page %s missing!" % os.path.join(self.host, page), False)
fetch.close()
def cache_flush(self):
self.pagecache = {}
# Primitives
def screen_scrape(self, page, template):
self.cache_load(page)
match = re.compile(template).search(self.pagecache[page])
if match:
result = match.group(1)
else:
result = None
return result
def get_MAC_address(self, page, prefix):
return self.screen_scrape("", prefix+r":[^M]*\(MAC Address: *([^)]*)")
def set_flag(self, page, flag, value):
if value:
self.actions.append(page, flag, "1")
else:
self.actions.append(page, flag, "0")
def set_IP_address(self, page, cgi, role, ip):
ind = 0
for octet in ip.split("."):
self.actions.append(("", "F1", role + repr(ind+1), octet))
ind += 1
# Scrape configuration data off the main page
def get_firmware_version(self):
# This is fragile. There is no distinguishing tag before the firmware
# version, so we have to key off the pattern of the version number.
# Our model is ">1.44.2.1, Dec 20 2002<"
return self.screen_scrape("", ">([0-9.v]*, (" + \
LinksysSession.months + ")[^<]*)<", )
def get_LAN_MAC(self):
return self.get_MAC_address("", r"LAN IP Address")
def get_Wireless_MAC(self):
return self.get_MAC_address("", r"Wireless")
def get_WAN_MAC(self):
return self.get_MAC_address("", r"WAN Connection Type")
# Set configuration data on the main page
def set_host_name(self, name):
self.actions.append(("", "hostName", name))
def set_domain_name(self, name):
self.actions.append(("", "DomainName", name))
def set_LAN_IP(self, ip):
self.set_IP_address("", "ipAddr", ip)
def set_LAN_netmask(self, ip):
if not ip.startswith("255.255.255."):
raise ValueError
lastquad = ip.split(".")[-1]
if lastquad not in ("0", "128", "192", "240", "252"):
raise ValueError
self.actions.append("", "netMask", lastquad)
def set_wireless(self, flag):
self.set_flag("", "wirelessStatus")
def set_SSID(self, ssid):
self.actions.append(("", "wirelessESSID", ssid))
def set_SSID_broadcast(self, flag):
self.set_flag("", "broadcastSSID")
def set_channel(self, channel):
self.actions.append(("", "wirelessChannel", channel))
def set_WEP(self, flag):
self.set_flag("", "WepType")
# FIXME: Add support for setting WEP keys
def set_connection_type(self, type):
self.actions.append(("", "WANConnectionType", type))
def set_WAN_IP(self, ip):
self.set_IP_address("", "aliasIP", ip)
def set_WAN_netmask(self, ip):
self.set_IP_address("", "aliasMaskIP", ip)
def set_WAN_gateway_address(self, ip):
self.set_IP_address("", "routerIP", ip)
def set_DNS_server(self, index, ip):
self.set_IP_address("", "dns" + "ABC"[index], ip)
# Set configuration data on the password page
def set_password(self, str):
self.actions.append("Passwd.htm","sysPasswd", str)
self.actions.append("Passwd.htm","sysPasswdConfirm", str)
def set_UPnP(self, flag):
self.set_flag("Passwd.htm", "UPnP_Work")
def reset(self):
self.actions.append("Passwd.htm", "FactoryDefaults")
# DHCP features
def set_DHCP(self, flag):
if flag:
self.actions.append("DHCP.htm","dhcpStatus","Enable")
else:
self.actions.append("DHCP.htm","dhcpStatus","Disable")
def set_DHCP_starting_IP(self, val):
self.actions.append("DHCP.htm","dhcpS4", str(val))
def set_DHCP_users(self, val):
self.actions.append("DHCP.htm","dhcpLen", str(val))
def set_DHCP_lease_time(self, val):
self.actions.append("DHCP.htm","leaseTime", str(val))
def set_DHCP_DNS_server(self, index, ip):
self.set_IP_address("DHCP.htm", "dns" + "ABC"[index], ip)
# FIXME: add support for setting WINS key
# Logging features
def set_logging(self, flag):
if flag:
self.actions.append("Log.htm", "rLog", "Enable")
else:
self.actions.append("Log.htm", "rLog", "Disable")
def set_log_address(self, val):
self.actions.append("DHCP.htm","trapAddr3", str(val))
# The AOL parental control flag is not supported by design.
# FIXME: add Filters and other advanced features
def configure(self):
"Write configuration changes to the Linksys."
if self.actions:
fields = []
self.cache_flush()
for (page, field, value) in self.actions:
self.cache_load(page)
if self.pagecache[page].find(field) == -1:
print_stderr("linksys: field %s not found where expected in page %s!" % (field, os.path.join(self.host, page)))
continue
else:
fields.append((field, value))
# Clearing the action list before fieldsping is deliberate.
# Otherwise we could get permanently wedged by a 401.
self.actions = []
transaction = curl.Curl(self.host)
transaction.set_verbosity(self.verbosity)
transaction.get("Gozila.cgi", tuple(fields))
transaction.close()
if __name__ == "__main__":
import os, cmd
class LinksysInterpreter(cmd.Cmd):
"""Interpret commands to perform LinkSys programming actions."""
def __init__(self):
cmd.Cmd.__init__(self)
self.session = LinksysSession()
if os.isatty(0):
print("Type ? or `help' for help.")
self.prompt = self.session.host + ": "
else:
self.prompt = ""
print("Bar1")
def flag_command(self, func, line):
if line.strip() in ("on", "enable", "yes"):
func(True)
elif line.strip() in ("off", "disable", "no"):
func(False)
else:
print_stderr("linksys: unknown switch value")
return 0
def do_connect(self, line):
newhost = line.strip()
if newhost:
self.session.host = newhost
self.session.cache_flush()
self.prompt = self.session.host + ": "
else:
print(self.session.host)
return 0
def help_connect(self):
print("Usage: connect []")
print("Connect to a Linksys by name or IP address.")
print("If no argument is given, print the current host.")
def do_status(self, line):
self.session.cache_load("")
if "" in self.session.pagecache:
print("Firmware:", self.session.get_firmware_version())
print("LAN MAC:", self.session.get_LAN_MAC())
print("Wireless MAC:", self.session.get_Wireless_MAC())
print("WAN MAC:", self.session.get_WAN_MAC())
print(".")
return 0
def help_status(self):
print("Usage: status")
print("The status command shows the status of the Linksys.")
print("It is mainly useful as a sanity check to make sure")
print("the box is responding correctly.")
def do_verbose(self, line):
self.flag_command(self.session.set_verbosity, line)
def help_verbose(self):
print("Usage: verbose {on|off|enable|disable|yes|no}")
print("Enables display of HTTP requests.")
def do_host(self, line):
self.session.set_host_name(line)
return 0
def help_host(self):
print("Usage: host ")
print("Sets the Host field to be queried by the ISP.")
def do_domain(self, line):
print("Usage: host ")
self.session.set_domain_name(line)
return 0
def help_domain(self):
print("Sets the Domain field to be queried by the ISP.")
def do_lan_address(self, line):
self.session.set_LAN_IP(line)
return 0
def help_lan_address(self):
print("Usage: lan_address ")
print("Sets the LAN IP address.")
def do_lan_netmask(self, line):
self.session.set_LAN_netmask(line)
return 0
def help_lan_netmask(self):
print("Usage: lan_netmask ")
print("Sets the LAN subnetwork mask.")
def do_wireless(self, line):
self.flag_command(self.session.set_wireless, line)
return 0
def help_wireless(self):
print("Usage: wireless {on|off|enable|disable|yes|no}")
print("Switch to enable or disable wireless features.")
def do_ssid(self, line):
self.session.set_SSID(line)
return 0
def help_ssid(self):
print("Usage: ssid ")
print("Sets the SSID used to control wireless access.")
def do_ssid_broadcast(self, line):
self.flag_command(self.session.set_SSID_broadcast, line)
return 0
def help_ssid_broadcast(self):
print("Usage: ssid_broadcast {on|off|enable|disable|yes|no}")
print("Switch to enable or disable SSID broadcast.")
def do_channel(self, line):
self.session.set_channel(line)
return 0
def help_channel(self):
print("Usage: channel ")
print("Sets the wireless channel.")
def do_wep(self, line):
self.flag_command(self.session.set_WEP, line)
return 0
def help_wep(self):
print("Usage: wep {on|off|enable|disable|yes|no}")
print("Switch to enable or disable WEP security.")
def do_wan_type(self, line):
try:
type=eval("LinksysSession.WAN_CONNECT_"+line.strip().upper())
self.session.set_connection_type(type)
except ValueError:
print_stderr("linksys: unknown connection type.")
return 0
def help_wan_type(self):
print("Usage: wan_type {auto|static|ppoe|ras|pptp|heartbeat}")
print("Set the WAN connection type.")
def do_wan_address(self, line):
self.session.set_WAN_IP(line)
return 0
def help_wan_address(self):
print("Usage: wan_address ")
print("Sets the WAN IP address.")
def do_wan_netmask(self, line):
self.session.set_WAN_netmask(line)
return 0
def help_wan_netmask(self):
print("Usage: wan_netmask ")
print("Sets the WAN subnetwork mask.")
def do_wan_gateway(self, line):
self.session.set_WAN_gateway(line)
return 0
def help_wan_gateway(self):
print("Usage: wan_gateway ")
print("Sets the LAN subnetwork mask.")
def do_dns(self, line):
(index, address) = line.split()
if index in ("1", "2", "3"):
self.session.set_DNS_server(eval(index), address)
else:
print_stderr("linksys: server index out of bounds.")
return 0
def help_dns(self):
print("Usage: dns {1|2|3} ")
print("Sets a primary, secondary, or tertiary DNS server address.")
def do_password(self, line):
self.session.set_password(line)
return 0
def help_password(self):
print("Usage: password ")
print("Sets the router password.")
def do_upnp(self, line):
self.flag_command(self.session.set_UPnP, line)
return 0
def help_upnp(self):
print("Usage: upnp {on|off|enable|disable|yes|no}")
print("Switch to enable or disable Universal Plug and Play.")
def do_reset(self, line):
self.session.reset()
def help_reset(self):
print("Usage: reset")
print("Reset Linksys settings to factory defaults.")
def do_dhcp(self, line):
self.flag_command(self.session.set_DHCP, line)
def help_dhcp(self):
print("Usage: dhcp {on|off|enable|disable|yes|no}")
print("Switch to enable or disable DHCP features.")
def do_dhcp_start(self, line):
self.session.set_DHCP_starting_IP(line)
def help_dhcp_start(self):
print("Usage: dhcp_start ")
print("Set the start address of the DHCP pool.")
def do_dhcp_users(self, line):
self.session.set_DHCP_users(line)
def help_dhcp_users(self):
print("Usage: dhcp_users ")
print("Set number of address slots to allocate in the DHCP pool.")
def do_dhcp_lease(self, line):
self.session.set_DHCP_lease(line)
def help_dhcp_lease(self):
print("Usage: dhcp_lease ")
print("Set number of address slots to allocate in the DHCP pool.")
def do_dhcp_dns(self, line):
(index, address) = line.split()
if index in ("1", "2", "3"):
self.session.set_DHCP_DNS_server(eval(index), address)
else:
print_stderr("linksys: server index out of bounds.")
return 0
def help_dhcp_dns(self):
print("Usage: dhcp_dns {1|2|3} ")
print("Sets primary, secondary, or tertiary DNS server address.")
def do_logging(self, line):
self.flag_command(self.session.set_logging, line)
def help_logging(self):
print("Usage: logging {on|off|enable|disable|yes|no}")
print("Switch to enable or disable session logging.")
def do_log_address(self, line):
self.session.set_Log_address(line)
def help_log_address(self):
print("Usage: log_address ")
print("Set the last quad of the address to which to log.")
def do_configure(self, line):
self.session.configure()
return 0
def help_configure(self):
print("Usage: configure")
print("Writes the configuration to the Linksys.")
def do_cache(self, line):
print(self.session.pagecache)
def help_cache(self):
print("Usage: cache")
print("Display the page cache.")
def do_quit(self, line):
return 1
def help_quit(self, line):
print("The quit command ends your linksys session without")
print("writing configuration changes to the Linksys.")
def do_EOF(self, line):
print("")
self.session.configure()
return 1
def help_EOF(self):
print("The EOF command writes the configuration to the linksys")
print("and ends your session.")
def default(self, line):
"""Pass the command through to be executed by the shell."""
os.system(line)
return 0
def help_help(self):
print("On-line help is available through this command.")
print("? is a convenience alias for help.")
def help_introduction(self):
print("""\
This program supports changing the settings on Linksys blue-box routers. This
capability may come in handy when they freeze up and have to be reset. Though
it can be used interactively (and will command-prompt when standard input is a
terminal) it is really designed to be used in batch mode. Commands are taken
from the command line first, then standard input.
By default, it is assumed that the Linksys is at http://192.168.1.1, the
default LAN address. You can connect to a different address or IP with the
'connect' command. Note that your .netrc must contain correct user/password
credentials for the router. The entry corresponding to the defaults is:
machine 192.168.1.1
login ""
password admin
Most commands queue up changes but don't actually send them to the Linksys.
You can force pending changes to be written with 'configure'. Otherwise, they
will be shipped to the Linksys at the end of session (e.g. when the program
running in batch mode encounters end-of-file or you type a control-D). If you
end the session with `quit', pending changes will be discarded.
For more help, read the topics 'wan', 'lan', and 'wireless'.""")
def help_lan(self):
print("""\
The `lan_address' and `lan_netmask' commands let you set the IP location of
the Linksys on your LAN, or inside. Normally you'll want to leave these
untouched.""")
def help_wan(self):
print("""\
The WAN commands become significant if you are using the BEFSR41 or any of
the other Linksys boxes designed as DSL or cable-modem gateways. You will
need to use `wan_type' to declare how you expect to get your address.
If your ISP has issued you a static address, you'll need to use the
`wan_address', `wan_netmask', and `wan_gateway' commands to set the address
of the router as seen from the WAN, the outside. In this case you will also
need to use the `dns' command to declare which remote servers your DNS
requests should be forwarded to.
Some ISPs may require you to set host and domain for use with dynamic-address
allocation.""")
def help_wireless_desc(self):
print("""\
The channel, ssid, ssid_broadcast, wep, and wireless commands control
wireless routing.""")
def help_switches(self):
print("Switches may be turned on with 'on', 'enable', or 'yes'.")
print("Switches may be turned off with 'off', 'disable', or 'no'.")
print("Switch commands include: wireless, ssid_broadcast.")
def help_addresses(self):
print("An address argument must be a valid IP address;")
print("four decimal numbers separated by dots, each ")
print("between 0 and 255.")
def emptyline(self):
pass
interpreter = LinksysInterpreter()
for arg in sys.argv[1:]:
interpreter.onecmd(arg)
fatal = False
while not fatal:
try:
interpreter.cmdloop()
fatal = True
except LinksysError:
message, fatal = sys.exc_info()[1].args
print("linksys: " + message)
# The following sets edit modes for GNU EMACS
# Local Variables:
# mode:python
# End:
pycurl-7.43.0.2/examples/sfquery.py 0000644 0001750 0001750 00000004631 13211045147 016177 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
#
# sfquery -- Source Forge query script using the ClientCGI high-level interface
#
# Retrieves a SourceForge XML export object for a given project.
# Specify the *numeric* project ID. the user name, and the password,
# as arguments. If you have a valid ~/.netrc entry for sourceforge.net,
# you can just give the project ID.
#
# By Eric S. Raymond, August 2002. All rites reversed.
import sys, netrc
import curl
class SourceForgeUserSession(curl.Curl):
# SourceForge-specific methods. Sensitive to changes in site design.
def login(self, name, password):
"Establish a login session."
self.post("account/login.php", (("form_loginname", name),
("form_pw", password),
("return_to", ""),
("stay_in_ssl", "1"),
("login", "Login With SSL")))
def logout(self):
"Log out of SourceForge."
self.get("account/logout.php")
def fetch_xml(self, numid):
self.get("export/xml_export.php?group_id=%s" % numid)
if __name__ == "__main__":
if len(sys.argv) == 1:
project_id = '28236' # PyCurl project ID
else:
project_id = sys.argv[1]
# Try to grab authenticators out of your .netrc
try:
auth = netrc.netrc().authenticators("sourceforge.net")
name, account, password = auth
except:
if len(sys.argv) < 4:
print("Usage: %s " % sys.argv[0])
raise SystemExit
name = sys.argv[2]
password = sys.argv[3]
session = SourceForgeUserSession("https://sourceforge.net/")
session.set_verbosity(0)
session.login(name, password)
# Login could fail.
if session.answered("Invalid Password or User Name"):
sys.stderr.write("Login/password not accepted (%d bytes)\n" % len(session.body()))
sys.exit(1)
# We'll see this if we get the right thing.
elif session.answered("Personal Page For: " + name):
session.fetch_xml(project_id)
sys.stdout.write(session.body())
session.logout()
sys.exit(0)
# Or maybe SourceForge has changed its site design so our check strings
# are no longer valid.
else:
sys.stderr.write("Unexpected page (%d bytes)\n"%len(session.body()))
sys.exit(1)
pycurl-7.43.0.2/examples/xmlrpc_curl.py 0000644 0001750 0001750 00000004203 13211045165 017026 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
except ImportError:
pass
else:
signal.signal(SIGPIPE, SIG_IGN)
try:
from cStringIO import StringIO
except ImportError:
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
try:
import xmlrpclib
except ImportError:
import xmlrpc.client as xmlrpclib
import pycurl
import sys
PY3 = sys.version_info[0] > 2
class CURLTransport(xmlrpclib.Transport):
"""Handles a cURL HTTP transaction to an XML-RPC server."""
xmlrpc_h = [ "Content-Type: text/xml" ]
def __init__(self, username=None, password=None):
self.c = pycurl.Curl()
self.c.setopt(pycurl.POST, 1)
self.c.setopt(pycurl.NOSIGNAL, 1)
self.c.setopt(pycurl.CONNECTTIMEOUT, 30)
self.c.setopt(pycurl.HTTPHEADER, self.xmlrpc_h)
if username != None and password != None:
self.c.setopt(pycurl.USERPWD, '%s:%s' % (username, password))
self._use_datetime = False
def request(self, host, handler, request_body, verbose=0):
b = StringIO()
self.c.setopt(pycurl.URL, 'http://%s%s' % (host, handler))
self.c.setopt(pycurl.POSTFIELDS, request_body)
self.c.setopt(pycurl.WRITEFUNCTION, b.write)
self.c.setopt(pycurl.VERBOSE, verbose)
self.verbose = verbose
try:
self.c.perform()
except pycurl.error:
v = sys.exc_info()[1]
if PY3:
v = v.args
raise xmlrpclib.ProtocolError(
host + handler,
v[0], v[1], None
)
b.seek(0)
return self.parse_response(b)
if __name__ == "__main__":
## Test
server = xmlrpclib.ServerProxy("http://betty.userland.com",
transport=CURLTransport())
print(server)
try:
print(server.examples.getStateName(41))
except xmlrpclib.Error:
v = sys.exc_info()[1]
print("ERROR", v)
pycurl-7.43.0.2/examples/retriever-multi.py 0000644 0001750 0001750 00000006437 13211045165 017646 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
#
# Usage: python retriever-multi.py [<# of
# concurrent connections>]
#
import sys
import pycurl
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
except ImportError:
pass
else:
signal.signal(SIGPIPE, SIG_IGN)
# Get args
num_conn = 10
try:
if sys.argv[1] == "-":
urls = sys.stdin.readlines()
else:
urls = open(sys.argv[1]).readlines()
if len(sys.argv) >= 3:
num_conn = int(sys.argv[2])
except:
print("Usage: %s [<# of concurrent connections>]" % sys.argv[0])
raise SystemExit
# Make a queue with (url, filename) tuples
queue = []
for url in urls:
url = url.strip()
if not url or url[0] == "#":
continue
filename = "doc_%03d.dat" % (len(queue) + 1)
queue.append((url, filename))
# Check args
assert queue, "no URLs given"
num_urls = len(queue)
num_conn = min(num_conn, num_urls)
assert 1 <= num_conn <= 10000, "invalid number of concurrent connections"
print("PycURL %s (compiled against 0x%x)" % (pycurl.version, pycurl.COMPILE_LIBCURL_VERSION_NUM))
print("----- Getting", num_urls, "URLs using", num_conn, "connections -----")
# Pre-allocate a list of curl objects
m = pycurl.CurlMulti()
m.handles = []
for i in range(num_conn):
c = pycurl.Curl()
c.fp = None
c.setopt(pycurl.FOLLOWLOCATION, 1)
c.setopt(pycurl.MAXREDIRS, 5)
c.setopt(pycurl.CONNECTTIMEOUT, 30)
c.setopt(pycurl.TIMEOUT, 300)
c.setopt(pycurl.NOSIGNAL, 1)
m.handles.append(c)
# Main loop
freelist = m.handles[:]
num_processed = 0
while num_processed < num_urls:
# If there is an url to process and a free curl object, add to multi stack
while queue and freelist:
url, filename = queue.pop(0)
c = freelist.pop()
c.fp = open(filename, "wb")
c.setopt(pycurl.URL, url)
c.setopt(pycurl.WRITEDATA, c.fp)
m.add_handle(c)
# store some info
c.filename = filename
c.url = url
# Run the internal curl state machine for the multi stack
while 1:
ret, num_handles = m.perform()
if ret != pycurl.E_CALL_MULTI_PERFORM:
break
# Check for curl objects which have terminated, and add them to the freelist
while 1:
num_q, ok_list, err_list = m.info_read()
for c in ok_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print("Success:", c.filename, c.url, c.getinfo(pycurl.EFFECTIVE_URL))
freelist.append(c)
for c, errno, errmsg in err_list:
c.fp.close()
c.fp = None
m.remove_handle(c)
print("Failed: ", c.filename, c.url, errno, errmsg)
freelist.append(c)
num_processed = num_processed + len(ok_list) + len(err_list)
if num_q == 0:
break
# Currently no more I/O is pending, could do something in the meantime
# (display a progress bar, etc.).
# We just call select() to sleep until some more data is available.
m.select(1.0)
# Cleanup
for c in m.handles:
if c.fp is not None:
c.fp.close()
c.fp = None
c.close()
m.close()
pycurl-7.43.0.2/examples/tests/ 0000755 0001750 0001750 00000000000 13304422066 015267 5 ustar me me 0000000 0000000 pycurl-7.43.0.2/examples/tests/test_xmlrpc.py 0000644 0001750 0001750 00000001355 13151540633 020212 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
## XML-RPC lib included in python2.2
try:
import xmlrpclib
except ImportError:
import xmlrpc.client as xmlrpclib
import pycurl
# Header fields passed in request
xmlrpc_header = [
"User-Agent: PycURL XML-RPC Test", "Content-Type: text/xml"
]
# XML-RPC request template
xmlrpc_template = """
%s%s
"""
# Engage
c = pycurl.Curl()
c.setopt(c.URL, 'http://betty.userland.com/RPC2')
c.setopt(c.POST, 1)
c.setopt(c.HTTPHEADER, xmlrpc_header)
c.setopt(c.POSTFIELDS, xmlrpc_template % ("examples.getStateName", xmlrpclib.dumps((5,))))
print('Response from http://betty.userland.com/')
c.perform()
c.close()
pycurl-7.43.0.2/examples/tests/test_gtk.py 0000644 0001750 0001750 00000005144 13211045165 017467 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
import sys, threading
import pycurl
import pygtk
pygtk.require('2.0')
import gtk
# We should ignore SIGPIPE when using pycurl.NOSIGNAL - see
# the libcurl tutorial for more info.
try:
import signal
from signal import SIGPIPE, SIG_IGN
except ImportError:
pass
else:
signal.signal(SIGPIPE, SIG_IGN)
class ProgressBar:
def __init__(self, uri):
self.round = 0.0
win = gtk.Window(gtk.WINDOW_TOPLEVEL)
win.set_title("PycURL progress")
win.show()
vbox = gtk.VBox(spacing=5)
vbox.set_border_width(10)
win.add(vbox)
win.set_default_size(200, 20)
vbox.show()
label = gtk.Label("Downloading %s" % uri)
label.set_alignment(0, 0.5)
vbox.pack_start(label)
label.show()
pbar = gtk.ProgressBar()
pbar.show()
self.pbar = pbar
vbox.pack_start(pbar)
win.connect("destroy", self.close_app)
def progress(self, download_t, download_d, upload_t, upload_d):
if download_t == 0:
self.round = self.round + 0.1
if self.round >= 1.0: self.round = 0.0
else:
self.round = float(download_d) / float(download_t)
gtk.threads_enter()
self.pbar.set_fraction(self.round)
gtk.threads_leave()
def mainloop(self):
gtk.threads_enter()
gtk.main()
gtk.threads_leave()
def close_app(self, *args):
args[0].destroy()
gtk.main_quit()
class Test(threading.Thread):
def __init__(self, url, target_file, progress):
threading.Thread.__init__(self)
self.target_file = target_file
self.progress = progress
self.curl = pycurl.Curl()
self.curl.setopt(pycurl.URL, url)
self.curl.setopt(pycurl.WRITEDATA, self.target_file)
self.curl.setopt(pycurl.FOLLOWLOCATION, 1)
self.curl.setopt(pycurl.NOPROGRESS, 0)
self.curl.setopt(pycurl.PROGRESSFUNCTION, self.progress)
self.curl.setopt(pycurl.MAXREDIRS, 5)
self.curl.setopt(pycurl.NOSIGNAL, 1)
def run(self):
self.curl.perform()
self.curl.close()
self.target_file.close()
self.progress(1.0, 1.0, 0, 0)
# Check command line args
if len(sys.argv) < 3:
print("Usage: %s " % sys.argv[0])
raise SystemExit
# Make a progress bar window
p = ProgressBar(sys.argv[1])
# Start thread for fetching url
Test(sys.argv[1], open(sys.argv[2], 'wb'), p.progress).start()
# Enter the GTK mainloop
gtk.threads_init()
try:
p.mainloop()
except KeyboardInterrupt:
pass
pycurl-7.43.0.2/examples/tests/test_build_config.py 0000644 0001750 0001750 00000003345 13211045161 021323 0 ustar me me 0000000 0000000 #! /usr/bin/env python
# -*- coding: utf-8 -*-
# vi:ts=4:et
import pycurl
import zlib
try:
from io import BytesIO
except ImportError:
try:
from cStringIO import StringIO as BytesIO
except ImportError:
from StringIO import StringIO as BytesIO
c = pycurl.Curl()
c.setopt(c.URL, 'http://pycurl.io')
#c.setopt(c.ENCODING, 'deflate')
c.setopt(c.HTTPHEADER, ['Accept-Encoding: deflate'])
body = BytesIO()
c.setopt(c.WRITEFUNCTION, body.write)
encoding_found = False
def header_function(header):
global encoding_found
if header.decode('iso-8859-1').lower().startswith('content-encoding: deflate'):
encoding_found = True
c.setopt(c.HEADERFUNCTION, header_function)
c.perform()
assert encoding_found
print('Server supports deflate encoding')
encoded = body.getvalue()
# should not raise exceptions
zlib.decompress(encoded, -zlib.MAX_WBITS)
print('Server served deflated body')
c.reset()
c.setopt(c.URL, 'http://pycurl.io')
c.setopt(c.ENCODING, 'deflate')
body = BytesIO()
c.setopt(c.WRITEFUNCTION, body.write)
encoding_found = False
def header_function(header):
global encoding_found
if header.decode('iso-8859-1').lower().startswith('content-encoding: deflate'):
encoding_found = True
c.setopt(c.HEADERFUNCTION, header_function)
c.perform()
assert encoding_found
print('Server claimed deflate encoding as expected')
# body should be decoded
encoded = body.getvalue()
if '