fix leaks / invalid frees
[m6w6/ext-http] / php_http_client.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-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14 #include "php_http_client.h"
15
16 #include <ext/spl/spl_observer.h>
17
18 /*
19 * array of name => php_http_client_driver_t*
20 */
21 static HashTable php_http_client_drivers;
22
23 static void php_http_client_driver_hash_dtor(zval *pData)
24 {
25 pefree(Z_PTR_P(pData), 1);
26 }
27
28 ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver)
29 {
30 return zend_hash_str_add_mem(&php_http_client_drivers, driver->name_str, driver->name_len, (void *) driver, sizeof(php_http_client_driver_t))
31 ? SUCCESS : FAILURE;
32 }
33
34 php_http_client_driver_t *php_http_client_driver_get(const char *name_str, size_t name_len)
35 {
36 zval *ztmp;
37 php_http_client_driver_t *tmp;
38
39 if (name_str && (tmp = zend_hash_str_find_ptr(&php_http_client_drivers, name_str, name_len))) {
40 return tmp;
41 }
42 if ((ztmp = zend_hash_get_current_data(&php_http_client_drivers))) {
43 return Z_PTR_P(ztmp);
44 }
45 return NULL;
46 }
47
48 static int apply_driver_list(zval *p, void *arg)
49 {
50 php_http_client_driver_t *d = Z_PTR_P(p);
51 zval zname;
52
53 ZVAL_STRINGL(&zname, d->name_str, d->name_len);
54
55 zend_hash_next_index_insert(arg, &zname);
56 return ZEND_HASH_APPLY_KEEP;
57 }
58
59 void php_http_client_driver_list(HashTable *ht)
60 {
61 zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht);
62 }
63
64 void php_http_client_options_set_subr(zval *instance, char *key, size_t len, zval *opts, int overwrite)
65 {
66 if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
67 zend_class_entry *this_ce = Z_OBJCE_P(instance);
68 zval *old_opts, new_opts, *entry = NULL;
69
70 array_init(&new_opts);
71 old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0);
72 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
73 array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
74 }
75
76 if (overwrite) {
77 if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
78 Z_ADDREF_P(opts);
79 zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
80 } else {
81 zend_symtable_str_del(Z_ARRVAL(new_opts), key, len);
82 }
83 } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
84 if ((entry = zend_symtable_str_find(Z_ARRVAL(new_opts), key, len))) {
85 array_join(Z_ARRVAL_P(opts), Z_ARRVAL_P(entry), 0, 0);
86 } else {
87 Z_ADDREF_P(opts);
88 zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
89 }
90 }
91
92 zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
93 zval_ptr_dtor(&new_opts);
94 }
95 }
96
97 void php_http_client_options_set(zval *instance, zval *opts)
98 {
99 php_http_arrkey_t key;
100 zval new_opts;
101 zend_class_entry *this_ce = Z_OBJCE_P(instance);
102 zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry);
103
104 array_init(&new_opts);
105
106 if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
107 zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
108 zval_ptr_dtor(&new_opts);
109 } else {
110 zval *old_opts, add_opts, *opt;
111
112 array_init(&add_opts);
113 /* some options need extra attention -- thus cannot use array_merge() directly */
114 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(opts), key.h, key.key, opt)
115 {
116 if (key.key) {
117 if (Z_TYPE_P(opt) == IS_ARRAY && (zend_string_equals_literal(key.key, "ssl") || zend_string_equals_literal(key.key, "cookies"))) {
118 php_http_client_options_set_subr(instance, key.key->val, key.key->len, opt, 0);
119 } else if (is_client && (zend_string_equals_literal(key.key, "recordHistory") || zend_string_equals_literal(key.key, "responseMessageClass"))) {
120 zend_update_property(this_ce, instance, key.key->val, key.key->len, opt);
121 } else if (Z_TYPE_P(opt) == IS_NULL) {
122 old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0);
123 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
124 zend_symtable_del(Z_ARRVAL_P(old_opts), key.key);
125 }
126 } else {
127 Z_TRY_ADDREF_P(opt);
128 add_assoc_zval_ex(&add_opts, key.key->val, key.key->len, opt);
129 }
130 }
131 }
132 ZEND_HASH_FOREACH_END();
133
134 old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0);
135 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
136 array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
137 }
138 array_join(Z_ARRVAL(add_opts), Z_ARRVAL(new_opts), 0, 0);
139 zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
140 zval_ptr_dtor(&new_opts);
141 zval_ptr_dtor(&add_opts);
142 }
143 }
144
145 void php_http_client_options_get_subr(zval *instance, char *key, size_t len, zval *return_value)
146 {
147 zend_class_entry *this_ce = Z_OBJCE_P(instance);
148 zval *options, *opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0);
149
150 if ((Z_TYPE_P(opts) == IS_ARRAY) && (options = zend_symtable_str_find(Z_ARRVAL_P(opts), key, len))) {
151 RETVAL_ZVAL_FAST(options);
152 }
153 }
154
155 static void queue_dtor(void *enqueued)
156 {
157 php_http_client_enqueue_t *e = enqueued;
158
159 if (e->dtor) {
160 e->dtor(e);
161 }
162 }
163
164 php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg)
165 {
166 php_http_client_t *free_h = NULL;
167
168 if (!h) {
169 free_h = h = emalloc(sizeof(*h));
170 }
171 memset(h, 0, sizeof(*h));
172
173 h->ops = ops;
174 if (rf) {
175 h->rf = rf;
176 } else if (ops->rsrc) {
177 h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL);
178 }
179 zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0);
180 zend_llist_init(&h->responses, sizeof(void *), NULL, 0);
181
182 if (h->ops->init) {
183 if (!(h = h->ops->init(h, init_arg))) {
184 php_error_docref(NULL, E_WARNING, "Could not initialize client");
185 PTR_FREE(free_h);
186 }
187 }
188
189 return h;
190 }
191
192 php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to)
193 {
194 if (from->ops->copy) {
195 return from->ops->copy(from, to);
196 }
197
198 return NULL;
199 }
200
201 void php_http_client_dtor(php_http_client_t *h)
202 {
203 php_http_client_reset(h);
204
205 if (h->ops->dtor) {
206 h->ops->dtor(h);
207 }
208
209 php_resource_factory_free(&h->rf);
210 }
211
212 void php_http_client_free(php_http_client_t **h) {
213 if (*h) {
214 php_http_client_dtor(*h);
215 efree(*h);
216 *h = NULL;
217 }
218 }
219
220 ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
221 {
222 if (h->ops->enqueue) {
223 if (php_http_client_enqueued(h, enqueue->request, NULL)) {
224 php_error_docref(NULL, E_WARNING, "Failed to enqueue request; request already in queue");
225 return FAILURE;
226 }
227 return h->ops->enqueue(h, enqueue);
228 }
229
230 return FAILURE;
231 }
232
233 ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request)
234 {
235 if (h->ops->dequeue) {
236 php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL);
237
238 if (!enqueue) {
239 php_error_docref(NULL, E_WARNING, "Failed to dequeue request; request not in queue");
240 return FAILURE;
241 }
242 return h->ops->dequeue(h, enqueue);
243 }
244 return FAILURE;
245 }
246
247 php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func)
248 {
249 zend_llist_element *el = NULL;
250
251 if (compare_func) {
252 for (el = h->requests.head; el; el = el->next) {
253 if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) {
254 break;
255 }
256 }
257 } else {
258 for (el = h->requests.head; el; el = el->next) {
259 if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) {
260 break;
261 }
262 }
263 }
264 return el ? (php_http_client_enqueue_t *) el->data : NULL;
265 }
266
267 ZEND_RESULT_CODE php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout)
268 {
269 if (h->ops->wait) {
270 return h->ops->wait(h, custom_timeout);
271 }
272
273 return FAILURE;
274 }
275
276 int php_http_client_once(php_http_client_t *h)
277 {
278 if (h->ops->once) {
279 return h->ops->once(h);
280 }
281
282 return FAILURE;
283 }
284
285 ZEND_RESULT_CODE php_http_client_exec(php_http_client_t *h)
286 {
287 if (h->ops->exec) {
288 return h->ops->exec(h);
289 }
290
291 return FAILURE;
292 }
293
294 void php_http_client_reset(php_http_client_t *h)
295 {
296 if (h->ops->reset) {
297 h->ops->reset(h);
298 }
299
300 zend_llist_clean(&h->requests);
301 zend_llist_clean(&h->responses);
302 }
303
304 ZEND_RESULT_CODE php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
305 {
306 if (h->ops->setopt) {
307 return h->ops->setopt(h, opt, arg);
308 }
309
310 return FAILURE;
311 }
312
313 ZEND_RESULT_CODE php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr)
314 {
315 if (h->ops->getopt) {
316 return h->ops->getopt(h, opt, arg, res_ptr);
317 }
318 return FAILURE;
319 }
320
321 zend_class_entry *php_http_client_class_entry;
322 static zend_object_handlers php_http_client_object_handlers;
323
324 void php_http_client_object_free(zend_object *object)
325 {
326 php_http_client_object_t *o = PHP_HTTP_OBJ(object, NULL);
327
328 php_http_client_free(&o->client);
329 zend_object_std_dtor(object);
330 }
331
332 php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client)
333 {
334 php_http_client_object_t *o;
335
336 o = ecalloc(1, sizeof(php_http_client_object_t) + (ce->default_properties_count - 1) * sizeof(zval));
337 zend_object_std_init(&o->zo, ce);
338 object_properties_init(&o->zo, ce);
339
340 o->client = client;
341
342 o->zo.handlers = &php_http_client_object_handlers;
343
344 return o;
345 }
346
347 zend_object *php_http_client_object_new(zend_class_entry *ce)
348 {
349 return &php_http_client_object_new_ex(ce, NULL)->zo;
350 }
351
352 static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response)
353 {
354 zval new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0);
355 php_http_message_t *req_copy = php_http_message_copy(request, NULL);
356 php_http_message_t *res_copy = php_http_message_copy(response, NULL);
357 php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy);
358 php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_class_entry, zipped);
359
360 ZVAL_OBJ(&new_hist, &obj->zo);
361
362 if (Z_TYPE_P(old_hist) == IS_OBJECT) {
363 php_http_message_object_prepend(&new_hist, old_hist, 1);
364 }
365
366 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), &new_hist);
367 zval_ptr_dtor(&new_hist);
368 }
369
370 static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **request, php_http_message_t **response)
371 {
372 zend_bool dequeue = 0;
373 zval zclient;
374 php_http_message_t *msg;
375 php_http_client_progress_state_t *progress;
376
377 ZVAL_OBJ(&zclient, &((php_http_client_object_t*) arg)->zo);
378
379 if ((msg = *response)) {
380 php_http_message_object_t *msg_obj;
381 zval info, zresponse, zrequest;
382 HashTable *info_ht;
383
384 /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
385 php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
386
387 if (zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0))) {
388 handle_history(&zclient, *request, *response);
389 }
390
391 /* hard detach, redirects etc. are in the history */
392 php_http_message_free(&msg->parent);
393 *response = NULL;
394
395 msg_obj = php_http_message_object_new_ex(php_http_client_response_class_entry, msg);
396 ZVAL_OBJ(&zresponse, &msg_obj->zo);
397 ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1);
398
399 php_http_message_object_prepend(&zresponse, &zrequest, 1);
400
401 object_init(&info);
402 info_ht = HASH_OF(&info);
403 php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht);
404 zend_update_property(php_http_client_response_class_entry, &zresponse, ZEND_STRL("transferInfo"), &info);
405 zval_ptr_dtor(&info);
406
407 Z_ADDREF(zresponse);
408 zend_llist_add_element(&client->responses, &msg_obj);
409
410 if (e->closure.fci.size) {
411 zval retval;
412 zend_error_handling zeh;
413
414 ZVAL_UNDEF(&retval);
415 zend_fcall_info_argn(&e->closure.fci, 1, &zresponse);
416 zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
417 zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL);
418 zend_restore_error_handling(&zeh);
419 zend_fcall_info_argn(&e->closure.fci, 0);
420
421 if (Z_TYPE(retval) == IS_TRUE) {
422 dequeue = 1;
423 }
424 zval_ptr_dtor(&retval);
425 }
426
427 zval_ptr_dtor(&zresponse);
428 zval_ptr_dtor(&zrequest);
429 }
430
431 if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) {
432 progress->info = "finished";
433 progress->finished = 1;
434 client->callback.progress.func(client->callback.progress.arg, client, e, progress);
435 }
436
437 if (dequeue) {
438 php_http_client_dequeue(client, e->request);
439 }
440
441 return SUCCESS;
442 }
443
444 static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress)
445 {
446 zval zrequest, zprogress, retval, zclient;
447 zend_error_handling zeh;
448
449 ZVAL_UNDEF(&retval);
450 ZVAL_OBJECT(&zclient, &((php_http_client_object_t *) arg)->zo, 1);
451 ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1);
452 object_init(&zprogress);
453 add_property_bool(&zprogress, "started", progress->started);
454 add_property_bool(&zprogress, "finished", progress->finished);
455 add_property_string(&zprogress, "info", STR_PTR(progress->info));
456 add_property_double(&zprogress, "dltotal", progress->dl.total);
457 add_property_double(&zprogress, "dlnow", progress->dl.now);
458 add_property_double(&zprogress, "ultotal", progress->ul.total);
459 add_property_double(&zprogress, "ulnow", progress->ul.now);
460 zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
461 zend_call_method_with_2_params(&zclient, NULL, NULL, "notify", &retval, &zrequest, &zprogress);
462 zend_restore_error_handling(&zeh);
463 zval_ptr_dtor(&zclient);
464 zval_ptr_dtor(&zrequest);
465 zval_ptr_dtor(&zprogress);
466 zval_ptr_dtor(&retval);
467 }
468
469 static void response_dtor(void *data)
470 {
471 php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data;
472
473 zend_objects_store_del(&msg_obj->zo);
474 }
475
476 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0)
477 ZEND_ARG_INFO(0, driver)
478 ZEND_ARG_INFO(0, persistent_handle_id)
479 ZEND_END_ARG_INFO();
480 static PHP_METHOD(HttpClient, __construct)
481 {
482 char *driver_str = NULL, *persistent_handle_str = NULL;
483 size_t driver_len = 0, persistent_handle_len = 0;
484 php_http_client_driver_t *driver;
485 php_resource_factory_t *rf = NULL;
486 php_http_client_object_t *obj;
487 zval os;
488
489 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!", &driver_str, &driver_len, &persistent_handle_str, &persistent_handle_len), invalid_arg, return);
490
491 if (!zend_hash_num_elements(&php_http_client_drivers)) {
492 php_http_throw(unexpected_val, "No http\\Client drivers available", NULL);
493 return;
494 }
495 if (!(driver = php_http_client_driver_get(driver_str, driver_len))) {
496 php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_len ? driver_str : "default");
497 return;
498 }
499
500 object_init_ex(&os, spl_ce_SplObjectStorage);
501 zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), &os);
502 zval_ptr_dtor(&os);
503
504 if (persistent_handle_len) {
505 char *name_str;
506 size_t name_len;
507 php_persistent_handle_factory_t *pf;
508
509 name_len = spprintf(&name_str, 0, "http\\Client\\%s", driver->name_str);
510 php_http_pretty_key(name_str + lenof("http\\Client\\"), driver->name_len, 1, 1);
511
512 if ((pf = php_persistent_handle_concede(NULL, name_str, name_len, persistent_handle_str, persistent_handle_len, NULL, NULL))) {
513 rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon);
514 }
515
516 efree(name_str);
517 }
518
519 obj = PHP_HTTP_OBJ(NULL, getThis());
520
521 php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return);
522
523 obj->client->callback.response.func = handle_response;
524 obj->client->callback.response.arg = obj;
525 obj->client->callback.progress.func = handle_progress;
526 obj->client->callback.progress.arg = obj;
527
528 obj->client->responses.dtor = response_dtor;
529 }
530
531 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0)
532 ZEND_END_ARG_INFO();
533 static PHP_METHOD(HttpClient, reset)
534 {
535 php_http_client_object_t *obj;
536 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
537
538 obj = PHP_HTTP_OBJ(NULL, getThis());
539
540 obj->iterator = 0;
541 php_http_client_reset(obj->client);
542
543 RETVAL_ZVAL_FAST(getThis());
544 }
545
546 static HashTable *combined_options(zval *client, zval *request)
547 {
548 HashTable *options;
549 unsigned num_options = 0;
550 zval z_roptions, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0);
551
552 if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
553 num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions));
554 }
555 ZVAL_UNDEF(&z_roptions);
556 zend_call_method_with_0_params(request, NULL, NULL, "getOptions", &z_roptions);
557 if (Z_TYPE(z_roptions) == IS_ARRAY) {
558 unsigned num = zend_hash_num_elements(Z_ARRVAL(z_roptions));
559 if (num > num_options) {
560 num_options = num;
561 }
562 }
563 ALLOC_HASHTABLE(options);
564 ZEND_INIT_SYMTABLE_EX(options, num_options, 0);
565 if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
566 array_copy(Z_ARRVAL_P(z_coptions), options);
567 }
568 if (Z_TYPE(z_roptions) == IS_ARRAY) {
569 array_join(Z_ARRVAL(z_roptions), options, 0, 0);
570 }
571 zval_ptr_dtor(&z_roptions);
572
573 return options;
574 }
575
576 static void msg_queue_dtor(php_http_client_enqueue_t *e)
577 {
578 php_http_message_object_t *msg_obj = e->opaque;
579
580 zend_objects_store_del(&msg_obj->zo);
581 zend_hash_destroy(e->options);
582 FREE_HASHTABLE(e->options);
583
584 if (e->closure.fci.size) {
585 zval_ptr_dtor(&e->closure.fci.function_name);
586 if (e->closure.fci.object) {
587 zend_objects_store_del(e->closure.fci.object);
588 }
589 }
590 }
591
592 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1)
593 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
594 ZEND_ARG_INFO(0, callable)
595 ZEND_END_ARG_INFO();
596 static PHP_METHOD(HttpClient, enqueue)
597 {
598 zval *request;
599 zend_fcall_info fci = empty_fcall_info;
600 zend_fcall_info_cache fcc = empty_fcall_info_cache;
601 php_http_client_object_t *obj;
602 php_http_message_object_t *msg_obj;
603 php_http_client_enqueue_t q;
604
605 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
606
607 obj = PHP_HTTP_OBJ(NULL, getThis());
608 msg_obj = PHP_HTTP_OBJ(NULL, request);
609
610 if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
611 php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL);
612 return;
613 }
614
615 q.request = msg_obj->message;
616 q.options = combined_options(getThis(), request);
617 q.dtor = msg_queue_dtor;
618 q.opaque = msg_obj;
619 q.closure.fci = fci;
620 q.closure.fcc = fcc;
621
622 if (fci.size) {
623 Z_TRY_ADDREF(fci.function_name);
624 if (fci.object) {
625 ++GC_REFCOUNT(fci.object);
626 }
627 }
628
629 Z_ADDREF_P(request);
630
631 php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
632 msg_queue_dtor(&q);
633 return;
634 );
635
636 RETVAL_ZVAL_FAST(getThis());
637 }
638
639 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1)
640 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
641 ZEND_END_ARG_INFO();
642 static PHP_METHOD(HttpClient, dequeue)
643 {
644 zval *request;
645 php_http_client_object_t *obj;
646 php_http_message_object_t *msg_obj;
647
648 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
649
650 obj = PHP_HTTP_OBJ(NULL, getThis());
651 msg_obj = PHP_HTTP_OBJ(NULL, request);
652
653 if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
654 php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL);
655 return;
656 }
657
658 php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
659
660 RETVAL_ZVAL_FAST(getThis());
661 }
662
663 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1)
664 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
665 ZEND_ARG_INFO(0, callable)
666 ZEND_END_ARG_INFO();
667 static PHP_METHOD(HttpClient, requeue)
668 {
669 zval *request;
670 zend_fcall_info fci = empty_fcall_info;
671 zend_fcall_info_cache fcc = empty_fcall_info_cache;
672 php_http_client_object_t *obj;
673 php_http_message_object_t *msg_obj;
674 php_http_client_enqueue_t q;
675
676 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
677
678 obj = PHP_HTTP_OBJ(NULL, getThis());
679 msg_obj = PHP_HTTP_OBJ(NULL, request);
680
681 if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
682 php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
683 }
684
685 q.request = msg_obj->message;
686 q.options = combined_options(getThis(), request);
687 q.dtor = msg_queue_dtor;
688 q.opaque = msg_obj;
689 q.closure.fci = fci;
690 q.closure.fcc = fcc;
691
692 if (fci.size) {
693 Z_TRY_ADDREF(fci.function_name);
694 if (fci.object) {
695 ++GC_REFCOUNT(fci.object);
696 }
697 }
698
699 Z_ADDREF_P(request);
700
701 php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
702 msg_queue_dtor(&q);
703 return;
704 );
705
706 RETVAL_ZVAL_FAST(getThis());
707 }
708
709 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0)
710 ZEND_END_ARG_INFO();
711 static PHP_METHOD(HttpClient, count)
712 {
713 zend_long count_mode = -1;
714
715 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
716 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
717
718 RETVAL_LONG(zend_llist_count(&obj->client->requests));
719 }
720 }
721
722 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0)
723 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
724 ZEND_END_ARG_INFO();
725 static PHP_METHOD(HttpClient, getResponse)
726 {
727 zval *zrequest = NULL;
728 php_http_client_object_t *obj;
729
730 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest, php_http_client_request_class_entry), invalid_arg, return);
731
732 obj = PHP_HTTP_OBJ(NULL, getThis());
733
734 if (zrequest) {
735 /* lookup the response with the request */
736 zend_llist_element *el = NULL;
737 php_http_message_object_t *req_obj = PHP_HTTP_OBJ(NULL, zrequest);
738
739 for (el = obj->client->responses.head; el; el = el->next) {
740 php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
741
742 if (response_obj->message->parent == req_obj->message) {
743 RETURN_OBJECT(&response_obj->zo, 1);
744 }
745 }
746
747 /* not found for the request! */
748 php_http_throw(unexpected_val, "Could not find response for the request", NULL);
749 return;
750 }
751
752 /* pop off the last response */
753 if (obj->client->responses.tail) {
754 php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data;
755
756 /* pop off and go */
757 if (response_obj) {
758 RETVAL_OBJECT(&response_obj->zo, 1);
759 zend_llist_remove_tail(&obj->client->responses);
760 }
761 }
762 }
763
764 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0)
765 ZEND_END_ARG_INFO();
766 static PHP_METHOD(HttpClient, getHistory)
767 {
768 zval *zhistory;
769
770 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
771
772 zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0);
773 RETVAL_ZVAL_FAST(zhistory);
774 }
775
776 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0)
777 ZEND_END_ARG_INFO();
778 static PHP_METHOD(HttpClient, send)
779 {
780 php_http_client_object_t *obj;
781
782 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
783
784 obj = PHP_HTTP_OBJ(NULL, getThis());
785
786 php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return);
787
788 RETVAL_ZVAL_FAST(getThis());
789 }
790
791 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0)
792 ZEND_END_ARG_INFO();
793 static PHP_METHOD(HttpClient, once)
794 {
795 if (SUCCESS == zend_parse_parameters_none()) {
796 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
797
798 RETURN_BOOL(0 < php_http_client_once(obj->client));
799 }
800 }
801
802 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0)
803 ZEND_ARG_INFO(0, timeout)
804 ZEND_END_ARG_INFO();
805 static PHP_METHOD(HttpClient, wait)
806 {
807 double timeout = 0;
808
809 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout)) {
810 struct timeval timeout_val;
811 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
812
813 timeout_val.tv_sec = (time_t) timeout;
814 timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
815
816 RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL));
817 }
818 }
819
820 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0)
821 ZEND_ARG_INFO(0, enable)
822 ZEND_END_ARG_INFO();
823 static PHP_METHOD(HttpClient, enablePipelining)
824 {
825 zend_bool enable = 1;
826 php_http_client_object_t *obj;
827
828 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
829
830 obj = PHP_HTTP_OBJ(NULL, getThis());
831
832 php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return);
833
834 RETVAL_ZVAL_FAST(getThis());
835 }
836
837 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0)
838 ZEND_ARG_INFO(0, enable)
839 ZEND_END_ARG_INFO();
840 static PHP_METHOD(HttpClient, enableEvents)
841 {
842 zend_bool enable = 1;
843 php_http_client_object_t *obj;
844
845 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
846
847 obj = PHP_HTTP_OBJ(NULL, getThis());
848
849 php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return);
850
851 RETVAL_ZVAL_FAST(getThis());
852 }
853
854 static int notify(zend_object_iterator *iter, void *puser)
855 {
856 zval *observer, *args = puser;
857
858 if ((observer = iter->funcs->get_current_data(iter))) {
859 int num_args = !Z_ISUNDEF(args[0]) + !Z_ISUNDEF(args[1]) + !Z_ISUNDEF(args[2]);
860 return php_http_method_call(observer, ZEND_STRL("update"), num_args, args, NULL);
861 }
862 return FAILURE;
863 }
864
865 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0)
866 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
867 ZEND_END_ARG_INFO();
868 static PHP_METHOD(HttpClient, notify)
869 {
870 zval *request = NULL, *zprogress = NULL, *observers, args[3];
871
872 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return);
873
874 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0);
875
876 if (Z_TYPE_P(observers) != IS_OBJECT) {
877 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
878 return;
879 }
880
881 ZVAL_COPY(&args[0], getThis());
882 if (request) {
883 ZVAL_COPY(&args[1], request);
884 } else {
885 ZVAL_UNDEF(&args[1]);
886 }
887 if (zprogress) {
888 ZVAL_COPY(&args[2], zprogress);
889 } else {
890 ZVAL_UNDEF(&args[2]);
891 }
892
893 spl_iterator_apply(observers, notify, args);
894
895 zval_ptr_dtor(getThis());
896 if (request) {
897 zval_ptr_dtor(request);
898 }
899 if (zprogress) {
900 zval_ptr_dtor(zprogress);
901 }
902
903 RETVAL_ZVAL_FAST(getThis());
904 }
905
906 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1)
907 ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
908 ZEND_END_ARG_INFO();
909 static PHP_METHOD(HttpClient, attach)
910 {
911 zval *observers, *observer, retval;
912
913 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
914
915 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0);
916
917 if (Z_TYPE_P(observers) != IS_OBJECT) {
918 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
919 return;
920 }
921
922 ZVAL_UNDEF(&retval);
923 zend_call_method_with_1_params(observers, NULL, NULL, "attach", &retval, observer);
924 zval_ptr_dtor(&retval);
925
926 RETVAL_ZVAL_FAST(getThis());
927 }
928
929 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1)
930 ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
931 ZEND_END_ARG_INFO();
932 static PHP_METHOD(HttpClient, detach)
933 {
934 zval *observers, *observer, retval;
935
936 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
937
938 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0);
939
940 if (Z_TYPE_P(observers) != IS_OBJECT) {
941 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
942 return;
943 }
944
945 ZVAL_UNDEF(&retval);
946 zend_call_method_with_1_params(observers, NULL, NULL, "detach", &retval, observer);
947 zval_ptr_dtor(&retval);
948
949 RETVAL_ZVAL_FAST(getThis());
950 }
951
952 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0)
953 ZEND_END_ARG_INFO();
954 static PHP_METHOD(HttpClient, getObservers)
955 {
956 zval *observers;
957
958 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
959
960 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0);
961
962 if (Z_TYPE_P(observers) != IS_OBJECT) {
963 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
964 return;
965 }
966
967 RETVAL_ZVAL_FAST(observers);
968 }
969
970 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1)
971 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
972 ZEND_END_ARG_INFO();
973 static PHP_METHOD(HttpClient, getProgressInfo)
974 {
975 zval *request;
976 php_http_client_object_t *obj;
977 php_http_message_object_t *req_obj;
978 php_http_client_progress_state_t *progress;
979
980 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
981
982 obj = PHP_HTTP_OBJ(NULL, getThis());
983 req_obj = PHP_HTTP_OBJ(NULL, request);
984
985 php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return);
986
987 object_init(return_value);
988 add_property_bool(return_value, "started", progress->started);
989 add_property_bool(return_value, "finished", progress->finished);
990 add_property_string(return_value, "info", STR_PTR(progress->info));
991 add_property_double(return_value, "dltotal", progress->dl.total);
992 add_property_double(return_value, "dlnow", progress->dl.now);
993 add_property_double(return_value, "ultotal", progress->ul.total);
994 add_property_double(return_value, "ulnow", progress->ul.now);
995 }
996
997 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1)
998 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
999 ZEND_END_ARG_INFO();
1000 static PHP_METHOD(HttpClient, getTransferInfo)
1001 {
1002 zval *request;
1003 HashTable *info;
1004 php_http_client_object_t *obj;
1005 php_http_message_object_t *req_obj;
1006
1007 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
1008
1009 obj = PHP_HTTP_OBJ(NULL, getThis());
1010 req_obj = PHP_HTTP_OBJ(NULL, request);
1011
1012 object_init(return_value);
1013 info = HASH_OF(return_value);
1014 php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return);
1015 }
1016
1017 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0)
1018 ZEND_ARG_ARRAY_INFO(0, options, 1)
1019 ZEND_END_ARG_INFO();
1020 static PHP_METHOD(HttpClient, setOptions)
1021 {
1022 zval *opts = NULL;
1023
1024 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1025
1026 php_http_client_options_set(getThis(), opts);
1027
1028 RETVAL_ZVAL_FAST(getThis());
1029 }
1030
1031 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0)
1032 ZEND_END_ARG_INFO();
1033 static PHP_METHOD(HttpClient, getOptions)
1034 {
1035 if (SUCCESS == zend_parse_parameters_none()) {
1036 zval *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0);
1037 RETVAL_ZVAL_FAST(options);
1038 }
1039 }
1040
1041 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0)
1042 ZEND_ARG_ARRAY_INFO(0, ssl_option, 1)
1043 ZEND_END_ARG_INFO();
1044 static PHP_METHOD(HttpClient, setSslOptions)
1045 {
1046 zval *opts = NULL;
1047
1048 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1049
1050 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1);
1051
1052 RETVAL_ZVAL_FAST(getThis());
1053 }
1054
1055 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0)
1056 ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
1057 ZEND_END_ARG_INFO();
1058 static PHP_METHOD(HttpClient, addSslOptions)
1059 {
1060 zval *opts = NULL;
1061
1062 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1063
1064 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0);
1065
1066 RETVAL_ZVAL_FAST(getThis());
1067 }
1068
1069 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0)
1070 ZEND_END_ARG_INFO();
1071 static PHP_METHOD(HttpClient, getSslOptions)
1072 {
1073 if (SUCCESS == zend_parse_parameters_none()) {
1074 php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value);
1075 }
1076 }
1077
1078 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0)
1079 ZEND_ARG_ARRAY_INFO(0, cookies, 1)
1080 ZEND_END_ARG_INFO();
1081 static PHP_METHOD(HttpClient, setCookies)
1082 {
1083 zval *opts = NULL;
1084
1085 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1086
1087 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 1);
1088
1089 RETVAL_ZVAL_FAST(getThis());
1090 }
1091
1092 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0)
1093 ZEND_ARG_ARRAY_INFO(0, cookies, 1)
1094 ZEND_END_ARG_INFO();
1095 static PHP_METHOD(HttpClient, addCookies)
1096 {
1097 zval *opts = NULL;
1098
1099 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1100
1101 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 0);
1102
1103 RETVAL_ZVAL_FAST(getThis());
1104 }
1105
1106 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0)
1107 ZEND_END_ARG_INFO();
1108 static PHP_METHOD(HttpClient, getCookies)
1109 {
1110 if (SUCCESS == zend_parse_parameters_none()) {
1111 php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value);
1112 }
1113 }
1114
1115 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0)
1116 ZEND_END_ARG_INFO();
1117 static PHP_METHOD(HttpClient, getAvailableDrivers)
1118 {
1119 if (SUCCESS == zend_parse_parameters_none()) {
1120 array_init(return_value);
1121 php_http_client_driver_list(Z_ARRVAL_P(return_value));
1122 }
1123 }
1124
1125 static zend_function_entry php_http_client_methods[] = {
1126 PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1127 PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC)
1128 PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC)
1129 PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC)
1130 PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC)
1131 PHP_ME(HttpClient, count, ai_HttpClient_count, ZEND_ACC_PUBLIC)
1132 PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC)
1133 PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC)
1134 PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC)
1135 PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC)
1136 PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC)
1137 PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC)
1138 PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC)
1139 PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC)
1140 PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC)
1141 PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC)
1142 PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC)
1143 PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC)
1144 PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC)
1145 PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC)
1146 PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC)
1147 PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC)
1148 PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC)
1149 PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC)
1150 PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC)
1151 PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC)
1152 PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC)
1153 PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1154 EMPTY_FUNCTION_ENTRY
1155 };
1156
1157 PHP_MINIT_FUNCTION(http_client)
1158 {
1159 zend_class_entry ce = {0};
1160
1161 INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods);
1162 php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL);
1163 php_http_client_class_entry->create_object = php_http_client_object_new;
1164 zend_class_implements(php_http_client_class_entry, 2, spl_ce_SplSubject, spl_ce_Countable);
1165 memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1166 php_http_client_object_handlers.offset = XtOffsetOf(php_http_client_object_t, zo);
1167 php_http_client_object_handlers.free_obj = php_http_client_object_free;
1168 php_http_client_object_handlers.clone_obj = NULL;
1169 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE);
1170 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED);
1171 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED);
1172 zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC);
1173
1174 zend_hash_init(&php_http_client_drivers, 2, NULL, php_http_client_driver_hash_dtor, 1);
1175
1176 return SUCCESS;
1177 }
1178
1179 PHP_MSHUTDOWN_FUNCTION(http_client)
1180 {
1181 zend_hash_destroy(&php_http_client_drivers);
1182 return SUCCESS;
1183 }
1184
1185 /*
1186 * Local variables:
1187 * tab-width: 4
1188 * c-basic-offset: 4
1189 * End:
1190 * vim600: noet sw=4 ts=4 fdm=marker
1191 * vim<600: noet sw=4 ts=4
1192 */