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