Index: setup.py =================================================================== RCS file: /cvsroot/pycurl/pycurl/setup.py,v retrieving revision 1.150 diff -u -r1.150 setup.py --- setup.py 9 Sep 2008 17:40:34 -0000 1.150 +++ setup.py 7 Nov 2009 03:48:31 -0000 @@ -9,7 +9,7 @@ PY_PACKAGE = "curl" VERSION = "7.19.0" -import glob, os, re, sys, string +import glob, os, re, sys, string, subprocess import distutils from distutils.core import setup from distutils.extension import Extension @@ -40,6 +40,19 @@ ##print sys.argv return p +CURL_CONFIG = None + +def run_curlconfig(options): + assert CURL_CONFIG is not None + p = subprocess.Popen("'%s' %s" % (CURL_CONFIG, options), shell=True, + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + (stdout, stderr) = p.communicate() + if p.wait() != 0: + raise RuntimeError("curl-config failed: \n%s\n%s" % + (stdout, stderr)) + else: + return stdout + # append contents of an environment variable to library_dirs[] def add_libdirs(envvar, sep, fatal=0): @@ -83,22 +96,35 @@ include_dirs.append(os.path.join(OPENSSL_DIR, "include")) CURL_CONFIG = "curl-config" CURL_CONFIG = scan_argv("--curl-config=", CURL_CONFIG) - d = os.popen("'%s' --version" % CURL_CONFIG).read() - if d: - d = string.strip(d) - if not d: + try: + d = run_curlconfig("--version") + except RuntimeError: raise Exception, ("`%s' not found -- please install the libcurl development files" % CURL_CONFIG) + d = string.strip(d) print "Using %s (%s)" % (CURL_CONFIG, d) - for e in split_quoted(os.popen("'%s' --cflags" % CURL_CONFIG).read()): + for e in split_quoted(run_curlconfig("--cflags")): if e[:2] == "-I": # do not add /usr/include if not re.search(r"^\/+usr\/+include\/*$", e[2:]): include_dirs.append(e[2:]) else: extra_compile_args.append(e) - libs = split_quoted( - os.popen("'%s' --libs" % CURL_CONFIG).read()+\ - os.popen("'%s' --static-libs" % CURL_CONFIG).read()) + + # Run curl-config --libs and curl-config --static-libs. Some platforms may + # not support one or the other of these curl-config options, so gracefully + # tolerate failure of one but not both. + # + # nb. that on platforms that supply both static and dynamic libs this can + # cause additional problems. + # + libs = run_curlconfig("--libs") + try: + libs += " " + run_curlconfig("--static-libs") + except RuntimeError: + pass + libs = split_quoted(libs) + + # Now create the list of libraries. for e in libs: if e[:2] == "-l": libraries.append(e[2:]) @@ -110,7 +136,8 @@ library_dirs.append(e[2:]) else: extra_link_args.append(e) - for e in split_quoted(os.popen("'%s' --features" % CURL_CONFIG).read()): + + for e in split_quoted(run_curlconfig("--features")): if e == 'SSL': define_macros.append(('HAVE_CURL_SSL', 1)) if not libraries: Index: src/pycurl.c =================================================================== RCS file: /cvsroot/pycurl/pycurl/src/pycurl.c,v retrieving revision 1.148 diff -u -r1.148 pycurl.c --- src/pycurl.c 29 Sep 2008 10:56:57 -0000 1.148 +++ src/pycurl.c 7 Nov 2009 03:48:31 -0000 @@ -739,64 +739,80 @@ return self; } - -/* constructor - this is a module-level function returning a new instance */ -static CurlObject * -do_curl_new(PyObject *dummy) +/* initializer - used to intialize curl easy handles for use with pycurl */ +static int +util_curl_init(CurlObject *self) { - CurlObject *self = NULL; int res; char *s = NULL; - UNUSED(dummy); - - /* Allocate python curl object */ - self = util_curl_new(); - if (self == NULL) - return NULL; - - /* Initialize curl handle */ - self->handle = curl_easy_init(); - if (self->handle == NULL) - goto error; - /* Set curl error buffer and zero it */ res = curl_easy_setopt(self->handle, CURLOPT_ERRORBUFFER, self->error); - if (res != CURLE_OK) - goto 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) - goto error; + 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) - goto error; + 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) - goto error; + 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) - goto error; + if (res != CURLE_OK) { + return (-1); + } /* Set default USERAGENT */ s = (char *) malloc(7 + strlen(LIBCURL_VERSION) + 1); - if (s == NULL) - goto error; + if (s == NULL) { + return (-1); + } strcpy(s, "PycURL/"); strcpy(s+7, LIBCURL_VERSION); res = curl_easy_setopt(self->handle, CURLOPT_USERAGENT, (char *) s); if (res != CURLE_OK) { free(s); - goto error; + return (-1); } + return (0); +} + +/* constructor - this is a module-level function returning a new instance */ +static CurlObject * +do_curl_new(PyObject *dummy) +{ + CurlObject *self = NULL; + int res; + + UNUSED(dummy); + + /* Allocate python curl object */ + self = util_curl_new(); + if (self == NULL) + return NULL; + + /* 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; @@ -1404,6 +1420,8 @@ static PyObject* do_curl_reset(CurlObject *self) { + int res; + curl_easy_reset(self->handle); /* Decref callbacks and file handles */ @@ -1421,10 +1439,19 @@ SFREE(self->postquote); SFREE(self->prequote); #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_INCREF(Py_None); return Py_None; } /* --------------- unsetopt/setopt/getinfo --------------- */ + int res; static PyObject * util_curl_unsetopt(CurlObject *self, int option) Index: tests/test_reset.py =================================================================== RCS file: tests/test_reset.py diff -N tests/test_reset.py --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ tests/test_reset.py 7 Nov 2009 03:48:31 -0000 @@ -0,0 +1,75 @@ +#!/usr/bin/python + +import sys +import pycurl + +saw_error = 1 + +def main(): + global saw_error + + pycurl.global_init(pycurl.GLOBAL_DEFAULT) + + outf = file("/dev/null", "rb+") + cm = pycurl.CurlMulti() + + # Set multi handle's options + cm.setopt(pycurl.M_PIPELINING, 1) + + eh = pycurl.Curl() + + for x in range(1, 20): + + eh.setopt(pycurl.WRITEDATA, outf) + eh.setopt(pycurl.URL, sys.argv[1]) + cm.add_handle(eh) + + while 1: + ret, active_handles = cm.perform() + if ret != pycurl.E_CALL_MULTI_PERFORM: + break + + while active_handles: + ret = cm.select(1.0) + if ret == -1: + continue + while 1: + ret, active_handles = cm.perform() + if ret != pycurl.E_CALL_MULTI_PERFORM: + break + + count, good, bad = cm.info_read() + + for h, en, em in bad: + print "Transfer to %s failed with %d, %s\n" % \ + (h.getinfo(pycurl.EFFECTIVE_URL), en, em) + raise RuntimeError + + for h in good: + httpcode = h.getinfo(pycurl.RESPONSE_CODE) + if httpcode != 200: + print "Transfer to %s failed with code %d\n" %\ + (h.getinfo(pycurl.EFFECTIVE_URL), httpcode) + raise RuntimeError + + else: + print "Recd %d bytes from %s" % \ + (h.getinfo(pycurl.SIZE_DOWNLOAD), + h.getinfo(pycurl.EFFECTIVE_URL)) + + cm.remove_handle(eh) + eh.reset() + + eh.close() + cm.close() + outf.close() + + pycurl.global_cleanup() + + +if __name__ == '__main__': + if len(sys.argv) != 2: + print "Usage: %s " % sys.argv[0] + sys.exit(2) + main() +