fix mime-type
[m6w6/ext-http] / php_http_request_datashare.c
1
2 #include "php_http.h"
3
4 static HashTable php_http_request_datashare_options;
5 static php_http_request_datashare_t php_http_request_datashare_global;
6 static int php_http_request_datashare_compare_handles(void *h1, void *h2);
7 static void php_http_request_datashare_destroy_handles(void *el);
8
9 #ifdef ZTS
10 static void *php_http_request_datashare_locks_init(void);
11 static void php_http_request_datashare_locks_dtor(void *l);
12 static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr);
13 static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr);
14 #endif
15
16 php_http_request_datashare_t *php_http_request_datashare_global_get(void)
17 {
18 return &php_http_request_datashare_global;
19 }
20
21 PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *share, zend_bool persistent TSRMLS_DC)
22 {
23 zend_bool free_share;
24
25 if ((free_share = !share)) {
26 share = pemalloc(sizeof(php_http_request_datashare_t), persistent);
27 }
28 memset(share, 0, sizeof(php_http_request_datashare_t));
29
30 if (SUCCESS != php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC)) {
31 if (free_share) {
32 pefree(share, persistent);
33 }
34 return NULL;
35 }
36
37 if (!(share->persistent = persistent)) {
38 share->handle.list = emalloc(sizeof(zend_llist));
39 zend_llist_init(share->handle.list, sizeof(zval *), ZVAL_PTR_DTOR, 0);
40 #ifdef ZTS
41 } else {
42 if (SUCCESS == php_http_persistent_handle_acquire(ZEND_STRL("http_request_datashare_lock"), (void *) &share->handle.locks)) {
43 curl_share_setopt(share->ch, CURLSHOPT_LOCKFUNC, php_http_request_datashare_lock_func);
44 curl_share_setopt(share->ch, CURLSHOPT_UNLOCKFUNC, php_http_request_datashare_unlock_func);
45 curl_share_setopt(share->ch, CURLSHOPT_USERDATA, share->handle.locks);
46 }
47 #endif
48 }
49
50 TSRMLS_SET_CTX(share->ts);
51
52 return share;
53 }
54
55 PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare_t *share, zval *request)
56 {
57 CURLcode rc;
58 TSRMLS_FETCH_FROM_CTX(share->ts);
59 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
60
61 if (obj->share) {
62 if (obj->share == share) {
63 return SUCCESS;
64 } else if (SUCCESS != php_http_request_datashare_detach(obj->share, request)) {
65 return FAILURE;
66 }
67 }
68
69 PHP_HTTP_CHECK_CURL_INIT(obj->request->ch, php_http_curl_init(obj->request->ch, obj->request TSRMLS_CC), return FAILURE);
70 if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, share->ch))) {
71 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not attach HttpRequest object(#%d) to the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_easy_strerror(rc));
72 return FAILURE;
73 }
74
75 obj->share = share;
76 Z_ADDREF_P(request);
77 zend_llist_add_element(PHP_HTTP_RSHARE_HANDLES(share), (void *) &request);
78
79 return SUCCESS;
80 }
81
82 PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare_t *share, zval *request)
83 {
84 CURLcode rc;
85 TSRMLS_FETCH_FROM_CTX(share->ts);
86 php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC);
87
88 if (!obj->share) {
89 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to any HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
90 } else if (obj->share != share) {
91 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "HttpRequest object(#%d) is not attached to this HttpRequestDataShare", Z_OBJ_HANDLE_P(request));
92 } else if (CURLE_OK != (rc = curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL))) {
93 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not detach HttpRequest object(#%d) from the HttpRequestDataShare: %s", Z_OBJ_HANDLE_P(request), curl_share_strerror(rc));
94 } else {
95 obj->share = NULL;
96 zend_llist_del_element(PHP_HTTP_RSHARE_HANDLES(share), request, php_http_request_datashare_compare_handles);
97 return SUCCESS;
98 }
99 return FAILURE;
100 }
101
102 PHP_HTTP_API void php_http_request_datashare_detach_all(php_http_request_datashare_t *share)
103 {
104 zval **r;
105
106 while ((r = zend_llist_get_first(PHP_HTTP_RSHARE_HANDLES(share)))) {
107 php_http_request_datashare_detach(share, *r);
108 }
109 }
110
111 PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *share)
112 {
113 TSRMLS_FETCH_FROM_CTX(share->ts);
114
115 if (!share->persistent) {
116 zend_llist_destroy(share->handle.list);
117 efree(share->handle.list);
118 }
119 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare"), &share->ch TSRMLS_CC);
120 #ifdef ZTS
121 if (share->persistent) {
122 php_http_persistent_handle_release(ZEND_STRL("http_request_datashare_lock"), (void *) &share->handle.locks TSRMLS_CC);
123 }
124 #endif
125 }
126
127 PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **share)
128 {
129 php_http_request_datashare_dtor(*share);
130 pefree(*share, (*share)->persistent);
131 *share = NULL;
132 }
133
134 PHP_HTTP_API STATUS php_http_request_datashare_set(php_http_request_datashare_t *share, const char *option, size_t option_len, zend_bool enable)
135 {
136 curl_lock_data *opt;
137 CURLSHcode rc;
138 TSRMLS_FETCH_FROM_CTX(share->ts);
139
140 if (SUCCESS == zend_hash_find(&php_http_request_datashare_options, (char *) option, option_len + 1, (void *) &opt)) {
141 if (CURLSHE_OK == (rc = curl_share_setopt(share->ch, enable ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, *opt))) {
142 return SUCCESS;
143 }
144 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not %s sharing of %s data: %s", enable ? "enable" : "disable", option, curl_share_strerror(rc));
145 }
146 return FAILURE;
147 }
148
149 static int php_http_request_datashare_compare_handles(void *h1, void *h2)
150 {
151 return (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
152 }
153
154 static void php_http_request_datashare_destroy_handles(void *el)
155 {
156 zval **r = (zval **) el;
157 TSRMLS_FETCH();
158
159 { /* gcc 2.95 needs these braces */
160 php_http_request_object_t *obj = zend_object_store_get_object(*r TSRMLS_CC);
161
162 curl_easy_setopt(obj->request->ch, CURLOPT_SHARE, NULL);
163 zval_ptr_dtor(r);
164 }
165 }
166
167 #ifdef ZTS
168 static void *php_http_request_datashare_locks_init(void)
169 {
170 int i;
171 php_http_request_datashare_lock_t *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(php_http_request_datashare_lock_t), 1);
172
173 if (locks) {
174 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
175 locks[i].mx = tsrm_mutex_alloc();
176 }
177 }
178
179 return locks;
180 }
181
182 static void php_http_request_datashare_locks_dtor(void *l)
183 {
184 int i;
185 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) l;
186
187 for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) {
188 tsrm_mutex_free(locks[i].mx);
189 }
190 pefree(locks, 1);
191 }
192
193 static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr)
194 {
195 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
196
197 /* TSRM can't distinguish shared/exclusive locks */
198 tsrm_mutex_lock(locks[data].mx);
199 locks[data].ch = handle;
200 }
201
202 static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr)
203 {
204 php_http_request_datashare_lock_t *locks = (php_http_request_datashare_lock_t *) userptr;
205
206 if (locks[data].ch == handle) {
207 tsrm_mutex_unlock(locks[data].mx);
208 }
209 }
210 #endif
211
212
213 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args)
214 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequestDataShare, method, 0)
215 #define PHP_HTTP_RSHARE_ME(method, visibility) PHP_ME(HttpRequestDataShare, method, PHP_HTTP_ARGS(HttpRequestDataShare, method), visibility)
216
217 PHP_HTTP_EMPTY_ARGS(__destruct);
218 PHP_HTTP_EMPTY_ARGS(count);
219
220 PHP_HTTP_BEGIN_ARGS(attach, 1)
221 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
222 PHP_HTTP_END_ARGS;
223 PHP_HTTP_BEGIN_ARGS(detach, 1)
224 PHP_HTTP_ARG_OBJ(http\\Request, request, 0)
225 PHP_HTTP_END_ARGS;
226
227 PHP_HTTP_EMPTY_ARGS(reset);
228
229 PHP_HTTP_EMPTY_ARGS(getGlobalInstance);
230
231
232 static zval *php_http_request_datashare_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC);
233 static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC);
234
235 #define THIS_CE php_http_request_datashare_class_entry
236 zend_class_entry *php_http_request_datashare_class_entry;
237 zend_function_entry php_http_request_datashare_method_entry[] = {
238 PHP_HTTP_RSHARE_ME(__destruct, ZEND_ACC_PUBLIC|ZEND_ACC_DTOR)
239 PHP_HTTP_RSHARE_ME(count, ZEND_ACC_PUBLIC)
240 PHP_HTTP_RSHARE_ME(attach, ZEND_ACC_PUBLIC)
241 PHP_HTTP_RSHARE_ME(detach, ZEND_ACC_PUBLIC)
242 PHP_HTTP_RSHARE_ME(reset, ZEND_ACC_PUBLIC)
243 PHP_HTTP_RSHARE_ME(getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
244 EMPTY_FUNCTION_ENTRY
245 };
246 static zend_object_handlers php_http_request_datashare_object_handlers;
247
248 zend_object_value php_http_request_datashare_object_new(zend_class_entry *ce TSRMLS_DC)
249 {
250 return php_http_request_datashare_object_new_ex(ce, NULL, NULL TSRMLS_CC);
251 }
252
253 zend_object_value php_http_request_datashare_object_new_ex(zend_class_entry *ce, php_http_request_datashare_t *share, php_http_request_datashare_object_t **ptr TSRMLS_DC)
254 {
255 zend_object_value ov;
256 php_http_request_datashare_object_t *o;
257
258 o = ecalloc(1, sizeof(*o));
259 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
260 object_properties_init((zend_object *) o, ce);
261
262 if (share) {
263 o->share = share;
264 } else {
265 o->share = php_http_request_datashare_init(NULL, 0 TSRMLS_CC);
266 }
267
268 if (ptr) {
269 *ptr = o;
270 }
271
272 ov.handle = zend_objects_store_put(o, NULL, php_http_request_datashare_object_free, NULL TSRMLS_CC);
273 ov.handlers = &php_http_request_datashare_object_handlers;
274
275 return ov;
276 }
277
278 void php_http_request_datashare_object_free(void *object TSRMLS_DC)
279 {
280 php_http_request_datashare_object_t *o = (php_http_request_datashare_object_t *) object;
281
282 if (!o->share->persistent) {
283 php_http_request_datashare_free(&o->share);
284 }
285 zend_object_std_dtor((zend_object *) o);
286 efree(o);
287 }
288
289 static zval *php_http_request_datashare_object_read_prop(zval *object, zval *member, int type, const zend_literal *literal_key TSRMLS_DC)
290 {
291 if (type == BP_VAR_W && zend_get_property_info(THIS_CE, member, 1 TSRMLS_CC)) {
292 zend_error(E_ERROR, "Cannot access HttpRequestDataShare default properties by reference or array key/index");
293 return NULL;
294 }
295
296 return zend_get_std_object_handlers()->read_property(object, member, type, literal_key TSRMLS_CC);
297 }
298
299 static void php_http_request_datashare_object_write_prop(zval *object, zval *member, zval *value, const zend_literal *literal_key TSRMLS_DC)
300 {
301 if (zend_get_property_info(THIS_CE, member, 1 TSRMLS_CC)) {
302 int status;
303 php_http_request_datashare_object_t *obj = zend_object_store_get_object(object TSRMLS_CC);
304
305 status = php_http_request_datashare_set(obj->share, Z_STRVAL_P(member), Z_STRLEN_P(member), (zend_bool) i_zend_is_true(value));
306 if (SUCCESS != status) {
307 return;
308 }
309 }
310
311 zend_get_std_object_handlers()->write_property(object, member, value, literal_key TSRMLS_CC);
312 }
313
314 PHP_METHOD(HttpRequestDataShare, __destruct)
315 {
316 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
317
318 if (SUCCESS == zend_parse_parameters_none()) {
319 ; /* we always want to clean up */
320 }
321
322 php_http_request_datashare_detach_all(obj->share);
323 }
324
325 PHP_METHOD(HttpRequestDataShare, count)
326 {
327 if (SUCCESS == zend_parse_parameters_none()) {
328 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
329
330 RETURN_LONG(zend_llist_count(PHP_HTTP_RSHARE_HANDLES(obj->share)));
331 }
332 RETURN_FALSE;
333 }
334
335
336 PHP_METHOD(HttpRequestDataShare, attach)
337 {
338 zval *request;
339
340 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
341 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
342
343 RETURN_SUCCESS(php_http_request_datashare_attach(obj->share, request));
344 }
345 RETURN_FALSE;
346
347 }
348
349 PHP_METHOD(HttpRequestDataShare, detach)
350 {
351 zval *request;
352
353 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, php_http_request_class_entry)) {
354 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
355
356 RETURN_SUCCESS(php_http_request_datashare_detach(obj->share, request));
357 }
358 RETURN_FALSE;
359 }
360
361 PHP_METHOD(HttpRequestDataShare, reset)
362 {
363 if (SUCCESS == zend_parse_parameters_none()) {
364 php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
365
366 php_http_request_datashare_detach_all(obj->share);
367 RETURN_TRUE;
368 }
369 RETURN_FALSE;
370 }
371
372 PHP_METHOD(HttpRequestDataShare, getGlobalInstance)
373 {
374 with_error_handling(EH_THROW, PHP_HTTP_EX_CE(runtime)) {
375 if (SUCCESS == zend_parse_parameters_none()) {
376 zval *instance = *zend_std_get_static_property(THIS_CE, ZEND_STRL("instance"), 0, NULL TSRMLS_CC);
377
378 if (Z_TYPE_P(instance) != IS_OBJECT) {
379 MAKE_STD_ZVAL(instance);
380 ZVAL_OBJVAL(instance, php_http_request_datashare_object_new_ex(THIS_CE, php_http_request_datashare_global_get(), NULL TSRMLS_CC), 1);
381 zend_update_static_property(THIS_CE, ZEND_STRL("instance"), instance TSRMLS_CC);
382
383 if (PHP_HTTP_G->request_datashare.cookie) {
384 zend_update_property_bool(THIS_CE, instance, ZEND_STRL("cookie"), PHP_HTTP_G->request_datashare.cookie TSRMLS_CC);
385 }
386 if (PHP_HTTP_G->request_datashare.dns) {
387 zend_update_property_bool(THIS_CE, instance, ZEND_STRL("dns"), PHP_HTTP_G->request_datashare.dns TSRMLS_CC);
388 }
389 if (PHP_HTTP_G->request_datashare.ssl) {
390 zend_update_property_bool(THIS_CE, instance, ZEND_STRL("ssl"), PHP_HTTP_G->request_datashare.ssl TSRMLS_CC);
391 }
392 if (PHP_HTTP_G->request_datashare.connect) {
393 zend_update_property_bool(THIS_CE, instance, ZEND_STRL("connect"), PHP_HTTP_G->request_datashare.connect TSRMLS_CC);
394 }
395 }
396
397 RETVAL_ZVAL(instance, 0, 0);
398 }
399 }end_error_handling();
400 }
401
402 PHP_MINIT_FUNCTION(http_request_datashare)
403 {
404 curl_lock_data val;
405
406 if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare"), curl_share_init, (php_http_persistent_handle_dtor_t) curl_share_cleanup, NULL)) {
407 return FAILURE;
408 }
409 #ifdef ZTS
410 if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_request_datashare_lock"), php_http_request_datashare_locks_init, php_http_request_datashare_locks_dtor, NULL)) {
411 return FAILURE;
412 }
413 #endif
414
415 if (!php_http_request_datashare_init(&php_http_request_datashare_global, 1 TSRMLS_CC)) {
416 return FAILURE;
417 }
418
419 zend_hash_init(&php_http_request_datashare_options, 4, NULL, NULL, 1);
420 #define ADD_DATASHARE_OPT(name, opt) \
421 val = opt; \
422 zend_hash_add(&php_http_request_datashare_options, name, sizeof(name), &val, sizeof(curl_lock_data), NULL)
423 ADD_DATASHARE_OPT("cookie", CURL_LOCK_DATA_COOKIE);
424 ADD_DATASHARE_OPT("dns", CURL_LOCK_DATA_DNS);
425 ADD_DATASHARE_OPT("ssl", CURL_LOCK_DATA_SSL_SESSION);
426 ADD_DATASHARE_OPT("connect", CURL_LOCK_DATA_CONNECT);
427
428 PHP_HTTP_REGISTER_CLASS(http\\request, DataShare, http_request_datashare, php_http_object_class_entry, 0);
429 php_http_request_datashare_class_entry->create_object = php_http_request_datashare_object_new;
430 memcpy(&php_http_request_datashare_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
431 php_http_request_datashare_object_handlers.clone_obj = NULL;
432 php_http_request_datashare_object_handlers.read_property = php_http_request_datashare_object_read_prop;
433 php_http_request_datashare_object_handlers.write_property = php_http_request_datashare_object_write_prop;
434 php_http_request_datashare_object_handlers.get_property_ptr_ptr = NULL;
435
436 zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable);
437
438 zend_declare_property_null(THIS_CE, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC);
439 zend_declare_property_bool(THIS_CE, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
440 zend_declare_property_bool(THIS_CE, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
441 zend_declare_property_bool(THIS_CE, ZEND_STRL("ssl"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
442 zend_declare_property_bool(THIS_CE, ZEND_STRL("connect"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
443
444 return SUCCESS;
445 }
446
447 PHP_MSHUTDOWN_FUNCTION(http_request_datashare)
448 {
449 php_http_request_datashare_dtor(&php_http_request_datashare_global);
450 zend_hash_destroy(&php_http_request_datashare_options);
451
452 return SUCCESS;
453 }
454
455 PHP_RINIT_FUNCTION(http_request_datashare)
456 {
457 zend_llist_init(&PHP_HTTP_G->request_datashare.handles, sizeof(zval *), php_http_request_datashare_destroy_handles, 0);
458
459 return SUCCESS;
460 }
461
462 PHP_RSHUTDOWN_FUNCTION(http_request_datashare)
463 {
464 zend_llist_destroy(&PHP_HTTP_G->request_datashare.handles);
465
466 return SUCCESS;
467 }
468