diff options
-rw-r--r-- | src/easy.c | 234 | ||||
-rw-r--r-- | src/easyopt.c | 46 | ||||
-rw-r--r-- | src/module.c | 13 | ||||
-rw-r--r-- | src/pycurl.h | 44 |
4 files changed, 243 insertions, 94 deletions
@@ -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; |