summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfsbs <fsbs@users.noreply.github.com>2021-10-31 04:06:36 +0000
committerfsbs <fsbs@users.noreply.github.com>2021-10-31 05:06:36 +0100
commite7d8329ad29a046488390a0d4d41e5878104cb75 (patch)
tree9bc5294a7dcdf376e1ca49a365bff11b56e29a53
parent23afe62edb66a751604974bef5dad63edd79d3de (diff)
downloadpycurl-e7d8329ad29a046488390a0d4d41e5878104cb75.tar.gz
Wrap curl_slist in a Python object
The goal is for each curl_slist to have its own reference count that is managed by Python. This allows for sharing of curl_slist data between cloned handles (curl_easy_duphandle).
-rw-r--r--src/easy.c127
-rw-r--r--src/easyopt.c30
-rw-r--r--src/module.c7
-rw-r--r--src/pycurl.h31
4 files changed, 118 insertions, 77 deletions
diff --git a/src/easy.c b/src/easy.c
index a22ad9c..9fd8be9 100644
--- a/src/easy.c
+++ b/src/easy.c
@@ -2,6 +2,41 @@
#include "docstrings.h"
/*************************************************************************
+// CurlSlistObject
+**************************************************************************/
+
+PYCURL_INTERNAL void
+util_curlslist_update(CurlSlistObject **old, struct curl_slist *slist)
+{
+ /* Decref previous object */
+ Py_XDECREF(*old);
+ /* Create a new object */
+ *old = PyObject_New(CurlSlistObject, p_CurlSlist_Type);
+ assert(*old != NULL);
+ /* Store curl_slist into the new object */
+ (*old)->slist = slist;
+}
+
+PYCURL_INTERNAL void
+do_curl_slist_dealloc(CurlSlistObject *self) {
+ if (self->slist != NULL) {
+ curl_slist_free_all(self->slist);
+ self->slist = NULL;
+ }
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+/* TODO: Python 2 compatible */
+PYCURL_INTERNAL PyTypeObject CurlSlist_Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ .tp_name = "pycurl.CurlSlist",
+ .tp_basicsize = sizeof(CurlSlistObject),
+ .tp_itemsize = 0,
+ .tp_dealloc = (destructor) do_curl_slist_dealloc,
+};
+
+
+/*************************************************************************
// static utility functions
**************************************************************************/
@@ -202,6 +237,28 @@ util_curl_xdecref(CurlObject *self, int flags, CURL *handle)
/* Decrement refcounts for ca certs related references. */
Py_CLEAR(self->ca_certs_obj);
}
+
+ if (flags & PYCURL_MEMGROUP_SLIST) {
+ /* Decrement refcounts for slist objects. */
+ Py_CLEAR(self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+ Py_CLEAR(self->proxyheader);
+#endif
+ Py_CLEAR(self->http200aliases);
+ Py_CLEAR(self->quote);
+ Py_CLEAR(self->postquote);
+ Py_CLEAR(self->prequote);
+ Py_CLEAR(self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+ Py_CLEAR(self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+ Py_CLEAR(self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+ Py_CLEAR(self->connect_to);
+#endif
+ }
}
@@ -247,32 +304,6 @@ util_curl_close(CurlObject *self)
if (self->weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject *) self);
}
-
- /* Free all variables allocated by setopt */
-#undef SFREE
-#define SFREE(v) if ((v) != NULL) (curl_formfree(v), (v) = NULL)
- SFREE(self->httppost);
-#undef SFREE
-#define SFREE(v) if ((v) != NULL) (curl_slist_free_all(v), (v) = NULL)
- SFREE(self->httpheader);
-#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
- SFREE(self->proxyheader);
-#endif
- SFREE(self->http200aliases);
- SFREE(self->quote);
- SFREE(self->postquote);
- SFREE(self->prequote);
- SFREE(self->telnetoptions);
-#ifdef HAVE_CURLOPT_RESOLVE
- SFREE(self->resolve);
-#endif
-#ifdef HAVE_CURL_7_20_0_OPTS
- SFREE(self->mail_rcpt);
-#endif
-#ifdef HAVE_CURLOPT_CONNECT_TO
- SFREE(self->connect_to);
-#endif
-#undef SFREE
}
@@ -351,6 +382,25 @@ do_curl_traverse(CurlObject *self, visitproc visit, void *arg)
VISIT(self->ca_certs_obj);
+ VISIT((PyObject *) self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+ VISIT((PyObject *) self->proxyheader);
+#endif
+ VISIT((PyObject *) self->http200aliases);
+ VISIT((PyObject *) self->quote);
+ VISIT((PyObject *) self->postquote);
+ VISIT((PyObject *) self->prequote);
+ VISIT((PyObject *) self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+ VISIT((PyObject *) self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+ VISIT((PyObject *) self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+ VISIT((PyObject *) self->connect_to);
+#endif
+
return 0;
#undef VISIT
}
@@ -368,31 +418,6 @@ do_curl_reset(CurlObject *self)
/* Decref easy interface related objects */
util_curl_xdecref(self, PYCURL_MEMGROUP_EASY, self->handle);
- /* Free all variables allocated by setopt */
-#undef SFREE
-#define SFREE(v) if ((v) != NULL) (curl_formfree(v), (v) = NULL)
- SFREE(self->httppost);
-#undef SFREE
-#define SFREE(v) if ((v) != NULL) (curl_slist_free_all(v), (v) = NULL)
- SFREE(self->httpheader);
-#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
- SFREE(self->proxyheader);
-#endif
- SFREE(self->http200aliases);
- SFREE(self->quote);
- SFREE(self->postquote);
- SFREE(self->prequote);
- SFREE(self->telnetoptions);
-#ifdef HAVE_CURLOPT_RESOLVE
- SFREE(self->resolve);
-#endif
-#ifdef HAVE_CURL_7_20_0_OPTS
- SFREE(self->mail_rcpt);
-#endif
-#ifdef HAVE_CURLOPT_CONNECT_TO
- SFREE(self->connect_to);
-#endif
-#undef SFREE
res = util_curl_init(self);
if (res < 0) {
Py_DECREF(self); /* this also closes self->handle */
diff --git a/src/easyopt.c b/src/easyopt.c
index ba4108c..5c6f29e 100644
--- a/src/easyopt.c
+++ b/src/easyopt.c
@@ -713,48 +713,48 @@ error:
static PyObject *
do_curl_setopt_list(CurlObject *self, int option, int which, PyObject *obj)
{
- struct curl_slist **old_slist = NULL;
+ CurlSlistObject **old_slist_obj = NULL;
struct curl_slist *slist = NULL;
Py_ssize_t len;
int res;
switch (option) {
case CURLOPT_HTTP200ALIASES:
- old_slist = &self->http200aliases;
+ old_slist_obj = &self->http200aliases;
break;
case CURLOPT_HTTPHEADER:
- old_slist = &self->httpheader;
+ old_slist_obj = &self->httpheader;
break;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
case CURLOPT_PROXYHEADER:
- old_slist = &self->proxyheader;
+ old_slist_obj = &self->proxyheader;
break;
#endif
case CURLOPT_POSTQUOTE:
- old_slist = &self->postquote;
+ old_slist_obj = &self->postquote;
break;
case CURLOPT_PREQUOTE:
- old_slist = &self->prequote;
+ old_slist_obj = &self->prequote;
break;
case CURLOPT_QUOTE:
- old_slist = &self->quote;
+ old_slist_obj = &self->quote;
break;
case CURLOPT_TELNETOPTIONS:
- old_slist = &self->telnetoptions;
+ old_slist_obj = &self->telnetoptions;
break;
#ifdef HAVE_CURLOPT_RESOLVE
case CURLOPT_RESOLVE:
- old_slist = &self->resolve;
+ old_slist_obj = &self->resolve;
break;
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
case CURLOPT_MAIL_RCPT:
- old_slist = &self->mail_rcpt;
+ old_slist_obj = &self->mail_rcpt;
break;
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
case CURLOPT_CONNECT_TO:
- old_slist = &self->connect_to;
+ old_slist_obj = &self->connect_to;
break;
#endif
default:
@@ -768,7 +768,7 @@ do_curl_setopt_list(CurlObject *self, int option, int which, PyObject *obj)
Py_RETURN_NONE;
/* Just to be sure we do not bug off here */
- assert(old_slist != NULL && slist == NULL);
+ assert(old_slist_obj != NULL && slist == NULL);
/* Handle regular list operations on the other options */
slist = pycurl_list_or_tuple_to_slist(which, obj, len);
@@ -781,9 +781,9 @@ do_curl_setopt_list(CurlObject *self, int option, int which, PyObject *obj)
curl_slist_free_all(slist);
CURLERROR_RETVAL();
}
- /* Finally, free previously allocated list and update */
- curl_slist_free_all(*old_slist);
- *old_slist = slist;
+ /* Finally, decref previous slist object and replace it with a
+ * new one. */
+ util_curlslist_update(old_slist_obj, slist);
Py_RETURN_NONE;
}
diff --git a/src/module.c b/src/module.c
index 2331168..2f40e98 100644
--- a/src/module.c
+++ b/src/module.c
@@ -28,6 +28,7 @@ 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_CurlSlist_Type = NULL;
PYCURL_INTERNAL PyTypeObject *p_CurlMulti_Type = NULL;
PYCURL_INTERNAL PyTypeObject *p_CurlShare_Type = NULL;
#ifdef HAVE_CURL_7_19_6_OPTS
@@ -416,9 +417,11 @@ initpycurl(void)
/* Initialize the type of the new type objects here; doing it here
* is required for portability to Windows without requiring C++. */
p_Curl_Type = &Curl_Type;
+ p_CurlSlist_Type = &CurlSlist_Type;
p_CurlMulti_Type = &CurlMulti_Type;
p_CurlShare_Type = &CurlShare_Type;
Py_SET_TYPE(&Curl_Type, &PyType_Type);
+ Py_SET_TYPE(&CurlSlist_Type, &PyType_Type);
Py_SET_TYPE(&CurlMulti_Type, &PyType_Type);
Py_SET_TYPE(&CurlShare_Type, &PyType_Type);
@@ -426,12 +429,16 @@ initpycurl(void)
if (PyType_Ready(&Curl_Type) < 0)
goto error;
+ if (PyType_Ready(&CurlSlist_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)
diff --git a/src/pycurl.h b/src/pycurl.h
index 31d1eac..f4f71f6 100644
--- a/src/pycurl.h
+++ b/src/pycurl.h
@@ -371,16 +371,23 @@ create_and_set_error_object(struct CurlObject *self, int code);
#define PYCURL_MEMGROUP_POSTFIELDS 64
/* CA certs object */
#define PYCURL_MEMGROUP_CACERTS 128
+/* Curl slist objects */
+#define PYCURL_MEMGROUP_SLIST 256
#define PYCURL_MEMGROUP_EASY \
(PYCURL_MEMGROUP_CALLBACK | PYCURL_MEMGROUP_FILE | \
PYCURL_MEMGROUP_HTTPPOST | PYCURL_MEMGROUP_POSTFIELDS | \
- PYCURL_MEMGROUP_CACERTS)
+ PYCURL_MEMGROUP_CACERTS | PYCURL_MEMGROUP_SLIST)
#define PYCURL_MEMGROUP_ALL \
(PYCURL_MEMGROUP_ATTRDICT | PYCURL_MEMGROUP_EASY | \
PYCURL_MEMGROUP_MULTI | PYCURL_MEMGROUP_SHARE)
+typedef struct CurlSlistObject {
+ PyObject_HEAD
+ struct curl_slist *slist;
+} CurlSlistObject;
+
typedef struct CurlObject {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
@@ -395,23 +402,23 @@ typedef struct CurlObject {
struct curl_httppost *httppost;
/* List of INC'ed references associated with httppost. */
PyObject *httppost_ref_list;
- struct curl_slist *httpheader;
+ struct CurlSlistObject *httpheader;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
- struct curl_slist *proxyheader;
+ struct CurlSlistObject *proxyheader;
#endif
- struct curl_slist *http200aliases;
- struct curl_slist *quote;
- struct curl_slist *postquote;
- struct curl_slist *prequote;
- struct curl_slist *telnetoptions;
+ struct CurlSlistObject *http200aliases;
+ struct CurlSlistObject *quote;
+ struct CurlSlistObject *postquote;
+ struct CurlSlistObject *prequote;
+ struct CurlSlistObject *telnetoptions;
#ifdef HAVE_CURLOPT_RESOLVE
- struct curl_slist *resolve;
+ struct CurlSlistObject *resolve;
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
- struct curl_slist *mail_rcpt;
+ struct CurlSlistObject *mail_rcpt;
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
- struct curl_slist *connect_to;
+ struct CurlSlistObject *connect_to;
#endif
/* callbacks */
PyObject *w_cb;
@@ -619,11 +626,13 @@ ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *ptr);
#if !defined(PYCURL_SINGLE_FILE)
/* Type objects */
extern PyTypeObject Curl_Type;
+extern PyTypeObject CurlSlist_Type;
extern PyTypeObject CurlMulti_Type;
extern PyTypeObject CurlShare_Type;
extern PyObject *ErrorObject;
extern PyTypeObject *p_Curl_Type;
+extern PyTypeObject *p_CurlSlist_Type;
extern PyTypeObject *p_CurlMulti_Type;
extern PyTypeObject *p_CurlShare_Type;
extern PyObject *khkey_type;