870e103382f58c39c67f9f515d4d1de1697aaf6a
[m6w6/ext-http] / http_request_datashare_api.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2006, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #define HTTP_WANT_CURL
16 #include "php_http.h"
17
18 #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL)
19
20 #include "php_http_api.h"
21 #include "php_http_request_datashare_api.h"
22 #include "php_http_request_api.h"
23 #include "php_http_request_object.h"
24
25 #ifndef HAVE_CURL_SHARE_STRERROR
26 # define curl_share_strerror(dummy) "unknown error"
27 #endif
28
29 static HashTable http_request_datashare_options;
30 static http_request_datashare http_request_datashare_global;
31 static int http_request_datashare_compare_handles(void *h1, void *h2);
32 static void http_request_datashare_destroy_handles(void *el);
33 #ifdef ZTS
34 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
35 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
36 #endif
37
38 http_request_datashare *_http_request_datashare_global_get(void)
39 {
40 return &http_request_datashare_global;
41 }
42
43 PHP_MINIT_FUNCTION(http_request_datashare)
44 {
45 curl_lock_data val;
46
47 zend_hash_init(&http_request_datashare_options, 4, NULL, NULL, 1);
48 #define ADD_DATASHARE_OPT(name, opt) \
49 val = opt; \
50 zend_hash_add(&http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
51 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
52 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
53 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
54 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
55
56 http_request_datashare_init_ex(&http_request_datashare_global, 1);
57
58 return SUCCESS;
59 }
60
61 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
62 {
63 http_request_datashare_dtor(&http_request_datashare_global);
64 zend_hash_destroy(&http_request_datashare_options);
65
66 return SUCCESS;
67 }
68
69 PHP_RINIT_FUNCTION(http_request_datashare)
70 {
71 zend_llist_init(&HTTP_G->request.datashare.handles, sizeof(zval *), http_request_datashare_destroy_handles, 0);
72
73 return SUCCESS;
74 }
75
76 PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
77 {
78 zend_llist_destroy(&HTTP_G->request.datashare.handles);
79
80 return SUCCESS;
81 }
82
83 PHP_HTTP_API http_request_datashare *_http_request_datashare_init_ex(http_request_datashare *share, zend_bool persistent TSRMLS_DC)
84 {
85 zend_bool free_share;
86
87 if ((free_share = !share)) {
88 share = pemalloc(sizeof(http_request_datashare), persistent);
89 }
90 memset(share, 0, sizeof(http_request_datashare));
91
92 HTTP_CHECK_CURL_INIT(share->ch, curl_share_init(), ;);
93 if (!share->ch) {
94 if (free_share) {
95 pefree(share, persistent);
96 }
97 return NULL;
98 }
99
100 if (!(share->persistent = persistent)) {
101 share->handles = emalloc(sizeof(zend_llist));
102 zend_llist_init(share->handles, sizeof(zval *), ZVAL_PTR_DTOR, 0);
103 #ifdef ZTS
104 } else {
105 int i;
106
107 share->locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(http_request_datashare_lock), 1);
108 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
109 share->locks[i].mx = tsrm_mutex_alloc();
110 }
111 curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, http_request_datashare_lock_func);
112 curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, http_request_datashare_unlock_func);
113 curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share);
114 #endif
115 }
116
117 return share;
118 }
119
120 PHP_HTTP_API STATUS _http_request_datashare_attach(http_request_datashare *share, zval *request TSRMLS_DC)
121 {
122 CURLcode rc;
123 getObjectEx(http_request_object, obj, request);
124
125 if (obj->share) {
126 if (obj->share == share) {
127 return SUCCESS;
128 } else if (SUCCESS != http_request_datashare_detach(obj->share, request)) {
129 return FAILURE;
130 }
131 }
132
133 if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
134 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
135 return FAILURE;
136 }
137
138 obj->share = share;
139 ZVAL_ADDREF(request);
140 zend_llist_add_element(HTTP_RSHARE_HANDLES(share), (void *) &request);
141
142 return SUCCESS;
143 }
144
145 PHP_HTTP_API STATUS _http_request_datashare_detach(http_request_datashare *share, zval *request TSRMLS_DC)
146 {
147 CURLcode rc;
148 getObjectEx(http_request_object, obj, request);
149
150 if (!obj->share) {
151 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
152 } else if (obj->share != share) {
153 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
154 } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
155 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
156 } else {
157 obj->share = NULL;
158 zend_llist_del_element(HTTP_RSHARE_HANDLES(share), request, http_request_datashare_compare_handles);
159 return SUCCESS;
160 }
161 return FAILURE;
162 }
163
164 PHP_HTTP_API void _http_request_datashare_detach_all(http_request_datashare *share TSRMLS_DC)
165 {
166 zval **r;
167
168 while ((r = zend_llist_get_first(HTTP_RSHARE_HANDLES(share)))) {
169 http_request_datashare_detach(share, *r);
170 }
171 }
172
173 PHP_HTTP_API void _http_request_datashare_dtor(http_request_datashare *share TSRMLS_DC)
174 {
175 if (!share->persistent) {
176 zend_llist_destroy(share->handles);
177 efree(share->handles);
178 }
179 curl_share_cleanup(share->ch);
180 #ifdef ZTS
181 if (share->persistent) {
182 int i;
183
184 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
185 tsrm_mutex_free(share->locks[i].mx);
186 }
187 pefree(share->locks, 1);
188 }
189 #endif
190 }
191
192 PHP_HTTP_API void _http_request_datashare_free(http_request_datashare **share TSRMLS_DC)
193 {
194 http_request_datashare_dtor(*share);
195 pefree(*share, (*share)->persistent);
196 *share = NULL;
197 }
198
199 PHP_HTTP_API STATUS _http_request_datashare_set(http_request_datashare *share, const char *option, size_t option_len, zend_bool enable TSRMLS_DC)
200 {
201 curl_lock_data *opt;
202 CURLSHcode rc;
203
204 if (SUCCESS == zend_hash_find(&http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
205 if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
206 return SUCCESS;
207 }
208 http_error_ex(HE_WARNING, HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
209 }
210 return FAILURE;
211 }
212
213 static int http_request_datashare_compare_handles(void *h1, void *h2)
214 {
215 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
216 }
217
218 static void http_request_datashare_destroy_handles(void *el)
219 {
220 zval **r = (zval **) el;
221 TSRMLS_FETCH();
222 getObjectEx(http_request_object, obj, *r);
223
224 curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
225 zval_ptr_dtor(r);
226 }
227
228 #ifdef ZTS
229 static void http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
230 {
231 http_request_datashare *share = (http_request_datashare *) userptr;
232
233 /* TSRM can't distinguish shared/exclusive locks */
234 tsrm_mutex_lock(share->locks[data].mx);
235 share->locks[data].ch = handle;
236 }
237
238 static void http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
239 {
240 http_request_datashare *share = (http_request_datashare *) userptr;
241
242 if (share->locks[data].ch == handle) {
243 tsrm_mutex_unlock(share->locks[data].mx);
244 }
245 }
246 #endif
247
248 #endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
249
250
251 /*
252 * Local variables:
253 * tab-width: 4
254 * c-basic-offset: 4
255 * End:
256 * vim600: noet sw=4 ts=4 fdm=marker
257 * vim<600: noet sw=4 ts=4
258 */
259