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