summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfsbs <fsbs@users.noreply.github.com>2021-10-31 11:48:54 +0100
committerfsbs <fsbs@users.noreply.github.com>2021-10-31 11:48:54 +0100
commit69aefc8a3b10ad50de963bbfda1d1e33c4d83d9b (patch)
tree2efa144f9c9d2045a76b5c525da6b23110303a7c
parentbdc7e4d3115824cc8eeebf8063939bf322703613 (diff)
parent2f2179a23be9b396cf6579a00020b171b81afe0c (diff)
downloadpycurl-69aefc8a3b10ad50de963bbfda1d1e33c4d83d9b.tar.gz
Merge branch 'py-wrap-slist-httppost' into add-easy-duphandle
-rw-r--r--src/easy.c234
-rw-r--r--src/easyopt.c46
-rw-r--r--src/module.c13
-rw-r--r--src/pycurl.h44
4 files changed, 243 insertions, 94 deletions
diff --git a/src/easy.c b/src/easy.c
index de7f13f..0d1204b 100644
--- a/src/easy.c
+++ b/src/easy.c
@@ -1,6 +1,142 @@
#include "pycurl.h"
#include "docstrings.h"
+#define PYCURL_TP_SLOTS_ZEROED \
+ 0, /* tp_print / tp_vectorcall_offset */ \
+ 0, /* tp_getattr */ \
+ 0, /* tp_setattr */ \
+ 0, /* tp_reserved / tp_as_async */ \
+ 0, /* tp_repr */ \
+ 0, /* tp_as_number */ \
+ 0, /* tp_as_sequence */ \
+ 0, /* tp_as_mapping */ \
+ 0, /* tp_hash */ \
+ 0, /* tp_call */ \
+ 0, /* tp_str */ \
+ 0, /* tp_getattro */ \
+ 0, /* tp_setattro */ \
+ 0, /* tp_as_buffer */ \
+ 0, /* tp_flags */ \
+ 0, /* tp_doc */ \
+ 0, /* tp_traverse */ \
+ 0, /* tp_clear */ \
+ 0, /* tp_richcompare */ \
+ 0, /* tp_weaklistoffset */ \
+ 0, /* tp_iter */ \
+ 0, /* tp_iternext */ \
+ 0, /* tp_methods */ \
+ 0, /* tp_members */ \
+ 0, /* tp_getset */ \
+ 0, /* tp_base */ \
+ 0, /* tp_dict */ \
+ 0, /* tp_descr_get */ \
+ 0, /* tp_descr_set */ \
+ 0, /* tp_dictoffset */ \
+ 0, /* tp_init */ \
+ 0, /* tp_alloc */ \
+ 0, /* tp_new */ \
+ 0, /* tp_free */ \
+ 0, /* tp_is_gc */ \
+ 0, /* tp_bases */ \
+ 0, /* tp_mro */ \
+ 0, /* tp_cache */ \
+ 0, /* tp_subclasses */ \
+ 0, /* tp_weaklist */
+
+/*************************************************************************
+// 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);
+}
+
+PYCURL_INTERNAL PyTypeObject CurlSlist_Type = {
+#if PY_MAJOR_VERSION >= 3
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+#endif
+ "pycurl.CurlSlist", /* tp_name */
+ sizeof(CurlSlistObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)do_curl_slist_dealloc, /* tp_dealloc */
+ PYCURL_TP_SLOTS_ZEROED
+#if PY_MAJOR_VERSION >= 3
+ 0, /* tp_del */
+ 0, /* tp_version_tag */
+ 0, /* tp_finalize */
+ 0, /* tp_vectorcall */
+#endif
+};
+
+
+/*************************************************************************
+// CurlHttppostObject
+**************************************************************************/
+
+PYCURL_INTERNAL void
+util_curlhttppost_update(CurlObject *obj, struct curl_httppost *httppost, PyObject *reflist)
+{
+ /* Decref previous object */
+ Py_XDECREF(obj->httppost);
+ /* Create a new object */
+ obj->httppost = PyObject_New(CurlHttppostObject, p_CurlHttppost_Type);
+ assert(obj->httppost != NULL);
+ /* Store curl_httppost and reflist into the new object */
+ obj->httppost->httppost = httppost;
+ obj->httppost->reflist = reflist;
+}
+
+PYCURL_INTERNAL void
+do_curl_httppost_dealloc(CurlHttppostObject *self) {
+ if (self->httppost != NULL) {
+ curl_formfree(self->httppost);
+ self->httppost = NULL;
+ }
+ Py_CLEAR(self->reflist);
+ Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+PYCURL_INTERNAL PyTypeObject CurlHttppost_Type = {
+#if PY_MAJOR_VERSION >= 3
+ PyVarObject_HEAD_INIT(NULL, 0)
+#else
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+#endif
+ "pycurl.CurlHttppost", /* tp_name */
+ sizeof(CurlHttppostObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)do_curl_httppost_dealloc, /* tp_dealloc */
+ PYCURL_TP_SLOTS_ZEROED
+#if PY_MAJOR_VERSION >= 3
+ 0, /* tp_del */
+ 0, /* tp_version_tag */
+ 0, /* tp_finalize */
+ 0, /* tp_vectorcall */
+#endif
+};
+
+
/*************************************************************************
// static utility functions
**************************************************************************/
@@ -414,14 +550,36 @@ util_curl_xdecref(CurlObject *self, int flags, CURL *handle)
}
if (flags & PYCURL_MEMGROUP_HTTPPOST) {
- /* Decrement refcounts for httppost related references. */
- Py_CLEAR(self->httppost_ref_list);
+ /* Decrement refcounts for httppost object. */
+ Py_CLEAR(self->httppost);
}
if (flags & PYCURL_MEMGROUP_CACERTS) {
/* Decrement refcounts for ca certs related references. */
Py_CLEAR(self->ca_certs_obj);
}
+
+ if (flags & PYCURL_MEMGROUP_SLIST) {
+ /* Decrement refcounts for slist objects. */
+ Py_CLEAR(self->httpheader);
+#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
+ Py_CLEAR(self->proxyheader);
+#endif
+ Py_CLEAR(self->http200aliases);
+ Py_CLEAR(self->quote);
+ Py_CLEAR(self->postquote);
+ Py_CLEAR(self->prequote);
+ Py_CLEAR(self->telnetoptions);
+#ifdef HAVE_CURLOPT_RESOLVE
+ Py_CLEAR(self->resolve);
+#endif
+#ifdef HAVE_CURL_7_20_0_OPTS
+ Py_CLEAR(self->mail_rcpt);
+#endif
+#ifdef HAVE_CURLOPT_CONNECT_TO
+ Py_CLEAR(self->connect_to);
+#endif
+ }
}
@@ -467,32 +625,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
}
@@ -571,6 +703,27 @@ 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
+
+ VISIT((PyObject *) self->httppost);
+
return 0;
#undef VISIT
}
@@ -588,31 +741,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..026eb46 100644
--- a/src/easyopt.c
+++ b/src/easyopt.c
@@ -67,8 +67,7 @@ util_curl_unsetopt(CurlObject *self, int option)
break;
case CURLOPT_HTTPPOST:
SETOPT((void *) 0);
- curl_formfree(self->httppost);
- util_curl_xdecref(self, PYCURL_MEMGROUP_HTTPPOST, self->handle);
+ Py_CLEAR(self->httppost);
self->httppost = NULL;
/* FIXME: what about data->set.httpreq ?? */
break;
@@ -690,16 +689,9 @@ do_curl_setopt_httppost(CurlObject *self, int option, int which, PyObject *obj)
CURLERROR_SET_RETVAL();
goto error;
}
- /* Finally, free previously allocated httppost, ZAP any
- * buffer references, and update */
- curl_formfree(self->httppost);
- util_curl_xdecref(self, PYCURL_MEMGROUP_HTTPPOST, self->handle);
- self->httppost = post;
-
- /* The previous list of INCed references was ZAPed above; save
- * the new one so that we can clean it up on the next
- * self->httppost free. */
- self->httppost_ref_list = ref_params;
+ /* Finally, decref previous httppost object and replace it with a
+ * new one. */
+ util_curlhttppost_update(self, post, ref_params);
Py_RETURN_NONE;
@@ -713,48 +705,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 +760,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 +773,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..24e8191 100644
--- a/src/module.c
+++ b/src/module.c
@@ -28,6 +28,8 @@ 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_CurlHttppost_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 +418,13 @@ initpycurl(void)
/* Initialize the type of the new type objects here; doing it here
* is required for portability to Windows without requiring C++. */
p_Curl_Type = &Curl_Type;
+ p_CurlSlist_Type = &CurlSlist_Type;
+ p_CurlHttppost_Type = &CurlHttppost_Type;
p_CurlMulti_Type = &CurlMulti_Type;
p_CurlShare_Type = &CurlShare_Type;
Py_SET_TYPE(&Curl_Type, &PyType_Type);
+ Py_SET_TYPE(&CurlSlist_Type, &PyType_Type);
+ Py_SET_TYPE(&CurlHttppost_Type, &PyType_Type);
Py_SET_TYPE(&CurlMulti_Type, &PyType_Type);
Py_SET_TYPE(&CurlShare_Type, &PyType_Type);
@@ -426,12 +432,19 @@ initpycurl(void)
if (PyType_Ready(&Curl_Type) < 0)
goto error;
+ if (PyType_Ready(&CurlSlist_Type) < 0)
+ goto error;
+
+ if (PyType_Ready(&CurlHttppost_Type) < 0)
+ goto error;
+
if (PyType_Ready(&CurlMulti_Type) < 0)
goto error;
if (PyType_Ready(&CurlShare_Type) < 0)
goto error;
+
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&curlmodule);
if (m == NULL)
diff --git a/src/pycurl.h b/src/pycurl.h
index 31d1eac..f5507de 100644
--- a/src/pycurl.h
+++ b/src/pycurl.h
@@ -371,16 +371,30 @@ 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 CurlHttppostObject {
+ PyObject_HEAD
+ struct curl_httppost *httppost;
+ /* List of INC'ed references associated with httppost. */
+ PyObject *reflist;
+} CurlHttppostObject;
+
typedef struct CurlObject {
PyObject_HEAD
PyObject *dict; /* Python attributes dictionary */
@@ -392,26 +406,24 @@ typedef struct CurlObject {
#endif
struct CurlMultiObject *multi_stack;
struct CurlShareObject *share;
- struct curl_httppost *httppost;
- /* List of INC'ed references associated with httppost. */
- PyObject *httppost_ref_list;
- struct curl_slist *httpheader;
+ struct CurlHttppostObject *httppost;
+ struct CurlSlistObject *httpheader;
#if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 37, 0)
- struct curl_slist *proxyheader;
+ struct CurlSlistObject *proxyheader;
#endif
- struct curl_slist *http200aliases;
- struct curl_slist *quote;
- struct curl_slist *postquote;
- struct curl_slist *prequote;
- struct curl_slist *telnetoptions;
+ struct CurlSlistObject *http200aliases;
+ struct CurlSlistObject *quote;
+ struct CurlSlistObject *postquote;
+ struct CurlSlistObject *prequote;
+ struct CurlSlistObject *telnetoptions;
#ifdef HAVE_CURLOPT_RESOLVE
- struct curl_slist *resolve;
+ struct CurlSlistObject *resolve;
#endif
#ifdef HAVE_CURL_7_20_0_OPTS
- struct curl_slist *mail_rcpt;
+ struct CurlSlistObject *mail_rcpt;
#endif
#ifdef HAVE_CURLOPT_CONNECT_TO
- struct curl_slist *connect_to;
+ struct CurlSlistObject *connect_to;
#endif
/* callbacks */
PyObject *w_cb;
@@ -619,11 +631,15 @@ 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 CurlHttppost_Type;
extern PyTypeObject CurlMulti_Type;
extern PyTypeObject CurlShare_Type;
extern PyObject *ErrorObject;
extern PyTypeObject *p_Curl_Type;
+extern PyTypeObject *p_CurlSlist_Type;
+extern PyTypeObject *p_CurlHttppost_Type;
extern PyTypeObject *p_CurlMulti_Type;
extern PyTypeObject *p_CurlShare_Type;
extern PyObject *khkey_type;