welcome back from vacation
[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_add_mem(&php_http_client_drivers, driver->driver_name, (void *) driver, sizeof(php_http_client_driver_t))
31 ? SUCCESS : FAILURE;
32 }
33
34 php_http_client_driver_t *php_http_client_driver_get(zend_string *name)
35 {
36 zval *ztmp;
37 php_http_client_driver_t *tmp;
38
39 if (name && (tmp = zend_hash_find_ptr(&php_http_client_drivers, name))) {
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_STR_COPY(&zname, d->driver_name);
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_tmp, *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, &old_opts_tmp);
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_tmp, *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, &old_opts_tmp);
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, &old_opts_tmp);
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_tmp, *opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &opts_tmp);
149
150 if ((Z_TYPE_P(opts) == IS_ARRAY) && (options = zend_symtable_str_find(Z_ARRVAL_P(opts), key, len))) {
151 RETVAL_ZVAL(options, 1, 0);
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 php_http_object_method_dtor(&o->notify);
330 php_http_object_method_free(&o->update);
331 zend_object_std_dtor(object);
332 }
333
334 php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client)
335 {
336 php_http_client_object_t *o;
337
338 o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
339 zend_object_std_init(&o->zo, ce);
340 object_properties_init(&o->zo, ce);
341
342 o->client = client;
343
344 o->zo.handlers = &php_http_client_object_handlers;
345
346 return o;
347 }
348
349 zend_object *php_http_client_object_new(zend_class_entry *ce)
350 {
351 return &php_http_client_object_new_ex(ce, NULL)->zo;
352 }
353
354 static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response)
355 {
356 zval new_hist, old_hist_tmp, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0, &old_hist_tmp);
357 php_http_message_t *req_copy = php_http_message_copy(request, NULL);
358 php_http_message_t *res_copy = php_http_message_copy(response, NULL);
359 php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy);
360 php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_class_entry, zipped);
361
362 ZVAL_OBJ(&new_hist, &obj->zo);
363
364 if (Z_TYPE_P(old_hist) == IS_OBJECT) {
365 php_http_message_object_prepend(&new_hist, old_hist, 1);
366 }
367
368 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), &new_hist);
369 zval_ptr_dtor(&new_hist);
370 }
371
372 static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **response)
373 {
374 zend_bool dequeue = 0;
375 zval zclient;
376 php_http_message_t *msg;
377 php_http_client_progress_state_t *progress;
378
379 ZVAL_OBJ(&zclient, &((php_http_client_object_t*) arg)->zo);
380
381 if ((msg = *response)) {
382 php_http_message_object_t *msg_obj;
383 zval info, zresponse, zrequest, rec_hist_tmp;
384 HashTable *info_ht;
385
386 /* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
387 php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
388
389 if (zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0, &rec_hist_tmp))) {
390 handle_history(&zclient, e->request, *response);
391 }
392
393 /* hard detach, redirects etc. are in the history */
394 php_http_message_free(&msg->parent);
395 *response = NULL;
396
397 msg_obj = php_http_message_object_new_ex(php_http_client_response_class_entry, msg);
398 ZVAL_OBJ(&zresponse, &msg_obj->zo);
399 ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1);
400
401 php_http_message_object_prepend(&zresponse, &zrequest, 1);
402
403 object_init(&info);
404 info_ht = HASH_OF(&info);
405 php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht);
406 zend_update_property(php_http_client_response_class_entry, &zresponse, ZEND_STRL("transferInfo"), &info);
407 zval_ptr_dtor(&info);
408
409 Z_ADDREF(zresponse);
410 zend_llist_add_element(&client->responses, &msg_obj);
411
412 if (e->closure.fci.size) {
413 zval retval;
414 zend_error_handling zeh;
415
416 ZVAL_UNDEF(&retval);
417 zend_fcall_info_argn(&e->closure.fci, 1, &zresponse);
418 zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
419 zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL);
420 zend_restore_error_handling(&zeh);
421 zend_fcall_info_argn(&e->closure.fci, 0);
422
423 if (Z_TYPE(retval) == IS_TRUE) {
424 dequeue = 1;
425 }
426 zval_ptr_dtor(&retval);
427 }
428
429 zval_ptr_dtor(&zresponse);
430 zval_ptr_dtor(&zrequest);
431 }
432
433 if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) {
434 progress->info = "finished";
435 progress->finished = 1;
436 client->callback.progress.func(client->callback.progress.arg, client, e, progress);
437 }
438
439 if (dequeue) {
440 php_http_client_dequeue(client, e->request);
441 }
442
443 return SUCCESS;
444 }
445
446 static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress)
447 {
448 zval zclient, args[2];
449 php_http_client_object_t *client_obj = arg;
450 zend_error_handling zeh;
451
452 ZVAL_OBJECT(&zclient, &client_obj->zo, 1);
453 ZVAL_OBJECT(&args[0], &((php_http_message_object_t *) e->opaque)->zo, 1);
454 object_init(&args[1]);
455 add_property_bool(&args[1], "started", progress->started);
456 add_property_bool(&args[1], "finished", progress->finished);
457 add_property_string(&args[1], "info", STR_PTR(progress->info));
458 add_property_double(&args[1], "dltotal", progress->dl.total);
459 add_property_double(&args[1], "dlnow", progress->dl.now);
460 add_property_double(&args[1], "ultotal", progress->ul.total);
461 add_property_double(&args[1], "ulnow", progress->ul.now);
462
463 zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
464 php_http_object_method_call(&client_obj->notify, &zclient, NULL, 2, args);
465 zend_restore_error_handling(&zeh);
466
467 zval_ptr_dtor(&zclient);
468 zval_ptr_dtor(&args[0]);
469 zval_ptr_dtor(&args[1]);
470 }
471
472 static void response_dtor(void *data)
473 {
474 php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data;
475
476 zend_objects_store_del(&msg_obj->zo);
477 }
478
479 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0)
480 ZEND_ARG_INFO(0, driver)
481 ZEND_ARG_INFO(0, persistent_handle_id)
482 ZEND_END_ARG_INFO();
483 static PHP_METHOD(HttpClient, __construct)
484 {
485 zend_string *driver_name = NULL, *persistent_handle_name = NULL;
486 php_http_client_driver_t *driver;
487 php_resource_factory_t *rf = NULL;
488 php_http_client_object_t *obj;
489 zval os;
490
491 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &driver_name, &persistent_handle_name), invalid_arg, return);
492
493 if (!zend_hash_num_elements(&php_http_client_drivers)) {
494 php_http_throw(unexpected_val, "No http\\Client drivers available", NULL);
495 return;
496 }
497 if (!(driver = php_http_client_driver_get(driver_name))) {
498 php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_name ? driver_name->val : "default");
499 return;
500 }
501
502 object_init_ex(&os, spl_ce_SplObjectStorage);
503 zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), &os);
504 zval_ptr_dtor(&os);
505
506 if (persistent_handle_name) {
507 php_persistent_handle_factory_t *pf;
508
509 if ((pf = php_persistent_handle_concede(NULL, driver->client_name, persistent_handle_name, NULL, NULL))) {
510 rf = php_persistent_handle_resource_factory_init(NULL, pf);
511 }
512 }
513
514 obj = PHP_HTTP_OBJ(NULL, getThis());
515
516 php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return);
517
518 php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify"));
519
520 obj->client->callback.response.func = handle_response;
521 obj->client->callback.response.arg = obj;
522 obj->client->callback.progress.func = handle_progress;
523 obj->client->callback.progress.arg = obj;
524
525 obj->client->responses.dtor = response_dtor;
526 }
527
528 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0)
529 ZEND_END_ARG_INFO();
530 static PHP_METHOD(HttpClient, reset)
531 {
532 php_http_client_object_t *obj;
533 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
534
535 obj = PHP_HTTP_OBJ(NULL, getThis());
536
537 obj->iterator = 0;
538 php_http_client_reset(obj->client);
539
540 RETVAL_ZVAL(getThis(), 1, 0);
541 }
542
543 static HashTable *combined_options(zval *client, zval *request)
544 {
545 HashTable *options;
546 unsigned num_options = 0;
547 zval z_roptions, z_options_tmp, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0, &z_options_tmp);
548
549 if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
550 num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions));
551 }
552 ZVAL_UNDEF(&z_roptions);
553 zend_call_method_with_0_params(request, NULL, NULL, "getOptions", &z_roptions);
554 if (Z_TYPE(z_roptions) == IS_ARRAY) {
555 unsigned num = zend_hash_num_elements(Z_ARRVAL(z_roptions));
556 if (num > num_options) {
557 num_options = num;
558 }
559 }
560 ALLOC_HASHTABLE(options);
561 ZEND_INIT_SYMTABLE_EX(options, num_options, 0);
562 if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
563 array_copy(Z_ARRVAL_P(z_coptions), options);
564 }
565 if (Z_TYPE(z_roptions) == IS_ARRAY) {
566 array_join(Z_ARRVAL(z_roptions), options, 0, 0);
567 }
568 zval_ptr_dtor(&z_roptions);
569
570 return options;
571 }
572
573 static void msg_queue_dtor(php_http_client_enqueue_t *e)
574 {
575 php_http_message_object_t *msg_obj = e->opaque;
576
577 zend_objects_store_del(&msg_obj->zo);
578 zend_hash_destroy(e->options);
579 FREE_HASHTABLE(e->options);
580
581 if (e->closure.fci.size) {
582 zval_ptr_dtor(&e->closure.fci.function_name);
583 if (e->closure.fci.object) {
584 zend_objects_store_del(e->closure.fci.object);
585 }
586 }
587 }
588
589 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1)
590 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
591 ZEND_ARG_INFO(0, callable)
592 ZEND_END_ARG_INFO();
593 static PHP_METHOD(HttpClient, enqueue)
594 {
595 zval *request;
596 zend_fcall_info fci = empty_fcall_info;
597 zend_fcall_info_cache fcc = empty_fcall_info_cache;
598 php_http_client_object_t *obj;
599 php_http_message_object_t *msg_obj;
600 php_http_client_enqueue_t q;
601
602 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
603
604 obj = PHP_HTTP_OBJ(NULL, getThis());
605 msg_obj = PHP_HTTP_OBJ(NULL, request);
606
607 if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
608 php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL);
609 return;
610 }
611
612 q.request = msg_obj->message;
613 q.options = combined_options(getThis(), request);
614 q.dtor = msg_queue_dtor;
615 q.opaque = msg_obj;
616 q.closure.fci = fci;
617 q.closure.fcc = fcc;
618
619 if (fci.size) {
620 Z_TRY_ADDREF(fci.function_name);
621 if (fci.object) {
622 ++GC_REFCOUNT(fci.object);
623 }
624 }
625
626 Z_ADDREF_P(request);
627
628 php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
629 msg_queue_dtor(&q);
630 return;
631 );
632
633 RETVAL_ZVAL(getThis(), 1, 0);
634 }
635
636 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1)
637 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
638 ZEND_END_ARG_INFO();
639 static PHP_METHOD(HttpClient, dequeue)
640 {
641 zval *request;
642 php_http_client_object_t *obj;
643 php_http_message_object_t *msg_obj;
644
645 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
646
647 obj = PHP_HTTP_OBJ(NULL, getThis());
648 msg_obj = PHP_HTTP_OBJ(NULL, request);
649
650 if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
651 php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL);
652 return;
653 }
654
655 php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
656
657 RETVAL_ZVAL(getThis(), 1, 0);
658 }
659
660 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1)
661 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
662 ZEND_ARG_INFO(0, callable)
663 ZEND_END_ARG_INFO();
664 static PHP_METHOD(HttpClient, requeue)
665 {
666 zval *request;
667 zend_fcall_info fci = empty_fcall_info;
668 zend_fcall_info_cache fcc = empty_fcall_info_cache;
669 php_http_client_object_t *obj;
670 php_http_message_object_t *msg_obj;
671 php_http_client_enqueue_t q;
672
673 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_client_request_class_entry, &fci, &fcc), invalid_arg, return);
674
675 obj = PHP_HTTP_OBJ(NULL, getThis());
676 msg_obj = PHP_HTTP_OBJ(NULL, request);
677
678 if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
679 php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
680 }
681
682 q.request = msg_obj->message;
683 q.options = combined_options(getThis(), request);
684 q.dtor = msg_queue_dtor;
685 q.opaque = msg_obj;
686 q.closure.fci = fci;
687 q.closure.fcc = fcc;
688
689 if (fci.size) {
690 Z_TRY_ADDREF(fci.function_name);
691 if (fci.object) {
692 ++GC_REFCOUNT(fci.object);
693 }
694 }
695
696 Z_ADDREF_P(request);
697
698 php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
699 msg_queue_dtor(&q);
700 return;
701 );
702
703 RETVAL_ZVAL(getThis(), 1, 0);
704 }
705
706 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0)
707 ZEND_END_ARG_INFO();
708 static PHP_METHOD(HttpClient, count)
709 {
710 zend_long count_mode = -1;
711
712 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
713 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
714
715 RETVAL_LONG(zend_llist_count(&obj->client->requests));
716 }
717 }
718
719 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0)
720 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
721 ZEND_END_ARG_INFO();
722 static PHP_METHOD(HttpClient, getResponse)
723 {
724 zval *zrequest = NULL;
725 php_http_client_object_t *obj;
726
727 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest, php_http_client_request_class_entry), invalid_arg, return);
728
729 obj = PHP_HTTP_OBJ(NULL, getThis());
730
731 if (zrequest) {
732 /* lookup the response with the request */
733 zend_llist_element *el = NULL;
734 php_http_message_object_t *req_obj = PHP_HTTP_OBJ(NULL, zrequest);
735
736 for (el = obj->client->responses.head; el; el = el->next) {
737 php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
738
739 if (response_obj->message->parent == req_obj->message) {
740 RETURN_OBJECT(&response_obj->zo, 1);
741 }
742 }
743
744 /* not found for the request! */
745 php_http_throw(unexpected_val, "Could not find response for the request", NULL);
746 return;
747 }
748
749 /* pop off the last response */
750 if (obj->client->responses.tail) {
751 php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data;
752
753 /* pop off and go */
754 if (response_obj) {
755 RETVAL_OBJECT(&response_obj->zo, 1);
756 zend_llist_remove_tail(&obj->client->responses);
757 }
758 }
759 }
760
761 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0)
762 ZEND_END_ARG_INFO();
763 static PHP_METHOD(HttpClient, getHistory)
764 {
765 zval zhistory_tmp, *zhistory;
766
767 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
768
769 zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0, &zhistory_tmp);
770 RETVAL_ZVAL(zhistory, 1, 0);
771 }
772
773 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0)
774 ZEND_END_ARG_INFO();
775 static PHP_METHOD(HttpClient, send)
776 {
777 php_http_client_object_t *obj;
778
779 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
780
781 obj = PHP_HTTP_OBJ(NULL, getThis());
782
783 php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return);
784
785 RETVAL_ZVAL(getThis(), 1, 0);
786 }
787
788 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0)
789 ZEND_END_ARG_INFO();
790 static PHP_METHOD(HttpClient, once)
791 {
792 if (SUCCESS == zend_parse_parameters_none()) {
793 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
794
795 RETURN_BOOL(0 < php_http_client_once(obj->client));
796 }
797 }
798
799 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0)
800 ZEND_ARG_INFO(0, timeout)
801 ZEND_END_ARG_INFO();
802 static PHP_METHOD(HttpClient, wait)
803 {
804 double timeout = 0;
805
806 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout)) {
807 struct timeval timeout_val;
808 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
809
810 timeout_val.tv_sec = (time_t) timeout;
811 timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
812
813 RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL));
814 }
815 }
816
817 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_configure, 0, 0, 1)
818 ZEND_ARG_ARRAY_INFO(0, settings, 1)
819 ZEND_END_ARG_INFO();
820 static PHP_METHOD(HttpClient, configure)
821 {
822 HashTable *settings = NULL;
823 php_http_client_object_t *obj;
824
825 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H!", &settings), invalid_arg, return);
826 obj = PHP_HTTP_OBJ(NULL, getThis());
827
828 php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_CONFIGURATION, settings), unexpected_val, return);
829
830 RETVAL_ZVAL(getThis(), 1, 0);
831 }
832
833 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0)
834 ZEND_ARG_INFO(0, enable)
835 ZEND_END_ARG_INFO();
836 static PHP_METHOD(HttpClient, enablePipelining)
837 {
838 zend_bool enable = 1;
839 php_http_client_object_t *obj;
840
841 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
842
843 obj = PHP_HTTP_OBJ(NULL, getThis());
844
845 php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return);
846
847 RETVAL_ZVAL(getThis(), 1, 0);
848 }
849
850 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0)
851 ZEND_ARG_INFO(0, enable)
852 ZEND_END_ARG_INFO();
853 static PHP_METHOD(HttpClient, enableEvents)
854 {
855 zend_bool enable = 1;
856 php_http_client_object_t *obj;
857
858 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
859
860 obj = PHP_HTTP_OBJ(NULL, getThis());
861
862 php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return);
863
864 RETVAL_ZVAL(getThis(), 1, 0);
865 }
866
867 struct notify_arg {
868 php_http_object_method_t *cb;
869 zval args[3];
870 int argc;
871 };
872
873 static int notify(zend_object_iterator *iter, void *puser)
874 {
875 zval *observer;
876 struct notify_arg *arg = puser;
877
878 if ((observer = iter->funcs->get_current_data(iter))) {
879 if (SUCCESS == php_http_object_method_call(arg->cb, observer, NULL, arg->argc, arg->args)) {
880 return ZEND_HASH_APPLY_KEEP;
881 }
882 }
883 return ZEND_HASH_APPLY_STOP;
884 }
885
886 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0)
887 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
888 ZEND_END_ARG_INFO();
889 static PHP_METHOD(HttpClient, notify)
890 {
891 zval *request = NULL, *zprogress = NULL, observers_tmp, *observers;
892 php_http_client_object_t *client_obj;
893 struct notify_arg arg = {NULL};
894
895 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_client_request_class_entry, &zprogress), invalid_arg, return);
896
897 client_obj = PHP_HTTP_OBJ(NULL, getThis());
898 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
899
900 if (Z_TYPE_P(observers) != IS_OBJECT) {
901 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
902 return;
903 }
904
905 if (client_obj->update) {
906 arg.cb = client_obj->update;
907 ZVAL_COPY(&arg.args[0], getThis());
908 arg.argc = 1;
909
910 if (request) {
911 ZVAL_COPY(&arg.args[1], request);
912 arg.argc += 1;
913 }
914 if (zprogress) {
915 ZVAL_COPY(&arg.args[2], zprogress);
916 arg.argc += 1;
917 }
918
919 spl_iterator_apply(observers, notify, &arg);
920
921 zval_ptr_dtor(getThis());
922 if (request) {
923 zval_ptr_dtor(request);
924 }
925 if (zprogress) {
926 zval_ptr_dtor(zprogress);
927 }
928 }
929
930 RETVAL_ZVAL(getThis(), 1, 0);
931 }
932
933 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1)
934 ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
935 ZEND_END_ARG_INFO();
936 static PHP_METHOD(HttpClient, attach)
937 {
938 zval observers_tmp, *observers, *observer, retval;
939 php_http_client_object_t *client_obj;
940
941 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
942
943 client_obj = PHP_HTTP_OBJ(NULL, getThis());
944 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
945
946 if (Z_TYPE_P(observers) != IS_OBJECT) {
947 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
948 return;
949 }
950
951 if (!client_obj->update) {
952 client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update"));
953 }
954
955 ZVAL_UNDEF(&retval);
956 zend_call_method_with_1_params(observers, NULL, NULL, "attach", &retval, observer);
957 zval_ptr_dtor(&retval);
958
959 RETVAL_ZVAL(getThis(), 1, 0);
960 }
961
962 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1)
963 ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
964 ZEND_END_ARG_INFO();
965 static PHP_METHOD(HttpClient, detach)
966 {
967 zval observers_tmp, *observers, *observer, retval;
968
969 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
970
971 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
972
973 if (Z_TYPE_P(observers) != IS_OBJECT) {
974 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
975 return;
976 }
977
978 ZVAL_UNDEF(&retval);
979 zend_call_method_with_1_params(observers, NULL, NULL, "detach", &retval, observer);
980 zval_ptr_dtor(&retval);
981
982 RETVAL_ZVAL(getThis(), 1, 0);
983 }
984
985 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0)
986 ZEND_END_ARG_INFO();
987 static PHP_METHOD(HttpClient, getObservers)
988 {
989 zval observers_tmp, *observers;
990
991 php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
992
993 observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
994
995 if (Z_TYPE_P(observers) != IS_OBJECT) {
996 php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
997 return;
998 }
999
1000 RETVAL_ZVAL(observers, 1, 0);
1001 }
1002
1003 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1)
1004 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
1005 ZEND_END_ARG_INFO();
1006 static PHP_METHOD(HttpClient, getProgressInfo)
1007 {
1008 zval *request;
1009 php_http_client_object_t *obj;
1010 php_http_message_object_t *req_obj;
1011 php_http_client_progress_state_t *progress;
1012
1013 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
1014
1015 obj = PHP_HTTP_OBJ(NULL, getThis());
1016 req_obj = PHP_HTTP_OBJ(NULL, request);
1017
1018 php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return);
1019
1020 object_init(return_value);
1021 add_property_bool(return_value, "started", progress->started);
1022 add_property_bool(return_value, "finished", progress->finished);
1023 add_property_string(return_value, "info", STR_PTR(progress->info));
1024 add_property_double(return_value, "dltotal", progress->dl.total);
1025 add_property_double(return_value, "dlnow", progress->dl.now);
1026 add_property_double(return_value, "ultotal", progress->ul.total);
1027 add_property_double(return_value, "ulnow", progress->ul.now);
1028 }
1029
1030 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1)
1031 ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
1032 ZEND_END_ARG_INFO();
1033 static PHP_METHOD(HttpClient, getTransferInfo)
1034 {
1035 zval *request;
1036 HashTable *info;
1037 php_http_client_object_t *obj;
1038 php_http_message_object_t *req_obj;
1039
1040 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_client_request_class_entry), invalid_arg, return);
1041
1042 obj = PHP_HTTP_OBJ(NULL, getThis());
1043 req_obj = PHP_HTTP_OBJ(NULL, request);
1044
1045 object_init(return_value);
1046 info = HASH_OF(return_value);
1047 php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return);
1048 }
1049
1050 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0)
1051 ZEND_ARG_ARRAY_INFO(0, options, 1)
1052 ZEND_END_ARG_INFO();
1053 static PHP_METHOD(HttpClient, setOptions)
1054 {
1055 zval *opts = NULL;
1056
1057 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1058
1059 php_http_client_options_set(getThis(), opts);
1060
1061 RETVAL_ZVAL(getThis(), 1, 0);
1062 }
1063
1064 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0)
1065 ZEND_END_ARG_INFO();
1066 static PHP_METHOD(HttpClient, getOptions)
1067 {
1068 if (SUCCESS == zend_parse_parameters_none()) {
1069 zval options_tmp, *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0, &options_tmp);
1070 RETVAL_ZVAL(options, 1, 0);
1071 }
1072 }
1073
1074 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0)
1075 ZEND_ARG_ARRAY_INFO(0, ssl_option, 1)
1076 ZEND_END_ARG_INFO();
1077 static PHP_METHOD(HttpClient, setSslOptions)
1078 {
1079 zval *opts = NULL;
1080
1081 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1082
1083 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1);
1084
1085 RETVAL_ZVAL(getThis(), 1, 0);
1086 }
1087
1088 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0)
1089 ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
1090 ZEND_END_ARG_INFO();
1091 static PHP_METHOD(HttpClient, addSslOptions)
1092 {
1093 zval *opts = NULL;
1094
1095 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1096
1097 php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0);
1098
1099 RETVAL_ZVAL(getThis(), 1, 0);
1100 }
1101
1102 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0)
1103 ZEND_END_ARG_INFO();
1104 static PHP_METHOD(HttpClient, getSslOptions)
1105 {
1106 if (SUCCESS == zend_parse_parameters_none()) {
1107 php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value);
1108 }
1109 }
1110
1111 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0)
1112 ZEND_ARG_ARRAY_INFO(0, cookies, 1)
1113 ZEND_END_ARG_INFO();
1114 static PHP_METHOD(HttpClient, setCookies)
1115 {
1116 zval *opts = NULL;
1117
1118 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1119
1120 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 1);
1121
1122 RETVAL_ZVAL(getThis(), 1, 0);
1123 }
1124
1125 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0)
1126 ZEND_ARG_ARRAY_INFO(0, cookies, 1)
1127 ZEND_END_ARG_INFO();
1128 static PHP_METHOD(HttpClient, addCookies)
1129 {
1130 zval *opts = NULL;
1131
1132 php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
1133
1134 php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 0);
1135
1136 RETVAL_ZVAL(getThis(), 1, 0);
1137 }
1138
1139 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0)
1140 ZEND_END_ARG_INFO();
1141 static PHP_METHOD(HttpClient, getCookies)
1142 {
1143 if (SUCCESS == zend_parse_parameters_none()) {
1144 php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value);
1145 }
1146 }
1147
1148 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0)
1149 ZEND_END_ARG_INFO();
1150 static PHP_METHOD(HttpClient, getAvailableDrivers)
1151 {
1152 if (SUCCESS == zend_parse_parameters_none()) {
1153 array_init(return_value);
1154 php_http_client_driver_list(Z_ARRVAL_P(return_value));
1155 }
1156 }
1157
1158 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableOptions, 0, 0, 0)
1159 ZEND_END_ARG_INFO();
1160 static PHP_METHOD(HttpClient, getAvailableOptions)
1161 {
1162 if (SUCCESS == zend_parse_parameters_none()) {
1163 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1164
1165 array_init(return_value);
1166 php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, NULL, &Z_ARRVAL_P(return_value));
1167 }
1168 }
1169
1170 ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableConfiguration, 0, 0, 0)
1171 ZEND_END_ARG_INFO();
1172 static PHP_METHOD(HttpClient, getAvailableConfiguration)
1173 {
1174 if (SUCCESS == zend_parse_parameters_none()) {
1175 php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
1176
1177 array_init(return_value);
1178 php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION, NULL, &Z_ARRVAL_P(return_value));
1179 }
1180 }
1181
1182 static zend_function_entry php_http_client_methods[] = {
1183 PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
1184 PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC)
1185 PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC)
1186 PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC)
1187 PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC)
1188 PHP_ME(HttpClient, count, ai_HttpClient_count, ZEND_ACC_PUBLIC)
1189 PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC)
1190 PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC)
1191 PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC)
1192 PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC)
1193 PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC)
1194 PHP_ME(HttpClient, configure, ai_HttpClient_configure, ZEND_ACC_PUBLIC)
1195 PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
1196 PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
1197 PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC)
1198 PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC)
1199 PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC)
1200 PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC)
1201 PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC)
1202 PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC)
1203 PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC)
1204 PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC)
1205 PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC)
1206 PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC)
1207 PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC)
1208 PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC)
1209 PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC)
1210 PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC)
1211 PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1212 PHP_ME(HttpClient, getAvailableOptions, ai_HttpClient_getAvailableOptions, ZEND_ACC_PUBLIC)
1213 PHP_ME(HttpClient, getAvailableConfiguration, ai_HttpClient_getAvailableConfiguration, ZEND_ACC_PUBLIC)
1214 EMPTY_FUNCTION_ENTRY
1215 };
1216
1217 PHP_MINIT_FUNCTION(http_client)
1218 {
1219 zend_class_entry ce = {0};
1220
1221 INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods);
1222 php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL);
1223 php_http_client_class_entry->create_object = php_http_client_object_new;
1224 zend_class_implements(php_http_client_class_entry, 2, spl_ce_SplSubject, spl_ce_Countable);
1225 memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
1226 php_http_client_object_handlers.offset = XtOffsetOf(php_http_client_object_t, zo);
1227 php_http_client_object_handlers.free_obj = php_http_client_object_free;
1228 php_http_client_object_handlers.clone_obj = NULL;
1229 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE);
1230 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED);
1231 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED);
1232 zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC);
1233
1234 zend_hash_init(&php_http_client_drivers, 2, NULL, php_http_client_driver_hash_dtor, 1);
1235
1236 return SUCCESS;
1237 }
1238
1239 PHP_MSHUTDOWN_FUNCTION(http_client)
1240 {
1241 zend_hash_destroy(&php_http_client_drivers);
1242 return SUCCESS;
1243 }
1244
1245 /*
1246 * Local variables:
1247 * tab-width: 4
1248 * c-basic-offset: 4
1249 * End:
1250 * vim600: noet sw=4 ts=4 fdm=marker
1251 * vim<600: noet sw=4 ts=4
1252 */