fix typo
[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-2011, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 #include <ext/spl/spl_observer.h>
16
17 PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg TSRMLS_DC)
18 {
19 php_http_client_t *free_h = NULL;
20
21 if (!h) {
22 free_h = h = emalloc(sizeof(*h));
23 }
24 memset(h, 0, sizeof(*h));
25
26 h->ops = ops;
27 if (rf) {
28 h->rf = rf;
29 } else if (ops->rsrc) {
30 h->rf = php_http_resource_factory_init(NULL, h->ops->rsrc, h, NULL);
31 }
32 h->request.buffer = php_http_buffer_init(NULL);
33 h->request.parser = php_http_message_parser_init(NULL TSRMLS_CC);
34 h->request.message = php_http_message_init(NULL, 0 TSRMLS_CC);
35
36 h->response.buffer = php_http_buffer_init(NULL);
37 h->response.parser = php_http_message_parser_init(NULL TSRMLS_CC);
38 h->response.message = php_http_message_init(NULL, 0 TSRMLS_CC);
39
40 TSRMLS_SET_CTX(h->ts);
41
42 if (h->ops->init) {
43 if (!(h = h->ops->init(h, init_arg))) {
44 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Could not initialize request");
45 if (free_h) {
46 h->ops->dtor = NULL;
47 php_http_client_free(&free_h);
48 }
49 }
50 }
51
52 return h;
53 }
54
55 PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h)
56 {
57 if (h->ops->dtor) {
58 h->ops->dtor(h);
59 }
60
61 php_http_resource_factory_free(&h->rf);
62
63 php_http_message_parser_free(&h->request.parser);
64 php_http_message_free(&h->request.message);
65 php_http_buffer_free(&h->request.buffer);
66
67 php_http_message_parser_free(&h->response.parser);
68 php_http_message_free(&h->response.message);
69 php_http_buffer_free(&h->response.buffer);
70 }
71
72 PHP_HTTP_API void php_http_client_free(php_http_client_t **h)
73 {
74 if (*h) {
75 php_http_client_dtor(*h);
76 efree(*h);
77 *h = NULL;
78 }
79 }
80
81 PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to)
82 {
83 if (!from->ops->copy) {
84 return NULL;
85 } else {
86 TSRMLS_FETCH_FROM_CTX(from->ts);
87
88 if (!to) {
89 to = ecalloc(1, sizeof(*to));
90 }
91
92 to->ops = from->ops;
93 if (from->rf) {
94 php_http_resource_factory_addref(from->rf);
95 to->rf = from->rf;
96 } else if (to->ops->rsrc){
97 to->rf = php_http_resource_factory_init(NULL, to->ops->rsrc, to, NULL);
98 }
99
100 to->request.buffer = php_http_buffer_init(NULL);
101 to->request.parser = php_http_message_parser_init(NULL TSRMLS_CC);
102 to->request.message = php_http_message_init(NULL, 0 TSRMLS_CC);
103
104 to->response.buffer = php_http_buffer_init(NULL);
105 to->response.parser = php_http_message_parser_init(NULL TSRMLS_CC);
106 to->response.message = php_http_message_init(NULL, 0 TSRMLS_CC);
107
108 TSRMLS_SET_CTX(to->ts);
109
110 return to->ops->copy(from, to);
111 }
112 }
113
114 PHP_HTTP_API STATUS php_http_client_exec(php_http_client_t *h, php_http_message_t *msg)
115 {
116 if (h->ops->exec) {
117 return h->ops->exec(h, msg);
118 }
119 return FAILURE;
120 }
121
122 PHP_HTTP_API STATUS php_http_client_reset(php_http_client_t *h)
123 {
124 if (h->ops->reset) {
125 return h->ops->reset(h);
126 }
127 return FAILURE;
128 }
129
130 PHP_HTTP_API STATUS php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
131 {
132 if (h->ops->setopt) {
133 return h->ops->setopt(h, opt, arg);
134 }
135 return FAILURE;
136 }
137
138 PHP_HTTP_API STATUS php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg)
139 {
140 if (h->ops->getopt) {
141 return h->ops->getopt(h, opt, arg);
142 }
143 return FAILURE;
144 }
145
146 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClient, method, 0, req_args)
147 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClient, method, 0)
148 #define PHP_HTTP_CLIENT_ME(method, visibility) PHP_ME(HttpClient, method, PHP_HTTP_ARGS(HttpClient, method), visibility)
149 #define PHP_HTTP_CLIENT_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClient, method))
150 #define PHP_HTTP_CLIENT_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##al), PHP_HTTP_ARGS(HttpClient, al), vis)
151
152 PHP_HTTP_BEGIN_ARGS(__construct, 0)
153 PHP_HTTP_ARG_ARR(options, 1, 0)
154 PHP_HTTP_END_ARGS;
155
156 PHP_HTTP_EMPTY_ARGS(getOptions);
157 PHP_HTTP_BEGIN_ARGS(setOptions, 0)
158 PHP_HTTP_ARG_ARR(options, 1, 0)
159 PHP_HTTP_END_ARGS;
160
161 PHP_HTTP_EMPTY_ARGS(getSslOptions);
162 PHP_HTTP_BEGIN_ARGS(setSslOptions, 0)
163 PHP_HTTP_ARG_ARR(ssl_options, 1, 0)
164 PHP_HTTP_END_ARGS;
165
166 PHP_HTTP_BEGIN_ARGS(addSslOptions, 0)
167 PHP_HTTP_ARG_ARR(ssl_options, 1, 0)
168 PHP_HTTP_END_ARGS;
169
170 PHP_HTTP_EMPTY_ARGS(getCookies);
171 PHP_HTTP_BEGIN_ARGS(setCookies, 0)
172 PHP_HTTP_ARG_VAL(cookies, 0)
173 PHP_HTTP_END_ARGS;
174
175 PHP_HTTP_BEGIN_ARGS(addCookies, 1)
176 PHP_HTTP_ARG_VAL(cookies, 0)
177 PHP_HTTP_END_ARGS;
178
179 PHP_HTTP_EMPTY_ARGS(enableCookies);
180 PHP_HTTP_BEGIN_ARGS(resetCookies, 0)
181 PHP_HTTP_ARG_VAL(session_only, 0)
182 PHP_HTTP_END_ARGS;
183 PHP_HTTP_EMPTY_ARGS(flushCookies);
184
185 PHP_HTTP_EMPTY_ARGS(getResponseMessageClass);
186 PHP_HTTP_BEGIN_ARGS(setResponseMessageClass, 1)
187 PHP_HTTP_ARG_VAL(message_class_name, 0)
188 PHP_HTTP_END_ARGS;
189
190 PHP_HTTP_EMPTY_ARGS(getResponseMessage);
191 PHP_HTTP_EMPTY_ARGS(getRequestMessage);
192 PHP_HTTP_EMPTY_ARGS(getHistory);
193 PHP_HTTP_EMPTY_ARGS(clearHistory);
194
195 PHP_HTTP_BEGIN_ARGS(setRequest, 1)
196 PHP_HTTP_ARG_OBJ(http\\Client\\Request, request, 1)
197 PHP_HTTP_END_ARGS;
198 PHP_HTTP_EMPTY_ARGS(getRequest);
199
200 PHP_HTTP_EMPTY_ARGS(getObservers);
201 PHP_HTTP_BEGIN_ARGS(attach, 1)
202 PHP_HTTP_ARG_OBJ(SplObserver, observer, 0)
203 PHP_HTTP_END_ARGS;
204 PHP_HTTP_BEGIN_ARGS(detach, 1)
205 PHP_HTTP_ARG_OBJ(SplObserver, observer, 0)
206 PHP_HTTP_END_ARGS;
207 PHP_HTTP_EMPTY_ARGS(notify);
208 PHP_HTTP_EMPTY_ARGS(getProgress);
209 PHP_HTTP_BEGIN_ARGS(getTransferInfo, 0)
210 PHP_HTTP_ARG_VAL(name, 0)
211 PHP_HTTP_END_ARGS;
212
213 PHP_HTTP_BEGIN_ARGS(request, 2)
214 PHP_HTTP_ARG_VAL(method, 0)
215 PHP_HTTP_ARG_VAL(url, 0)
216 PHP_HTTP_ARG_ARR(headers, 1, 0)
217 PHP_HTTP_ARG_VAL(body, 0)
218 PHP_HTTP_ARG_ARR(options, 1, 0)
219 PHP_HTTP_END_ARGS;
220
221 static zend_class_entry *php_http_client_class_entry;
222
223 zend_class_entry *php_http_client_get_class_entry(void)
224 {
225 return php_http_client_class_entry;
226 }
227
228 static zend_function_entry php_http_client_method_entry[] = {
229 PHP_HTTP_CLIENT_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
230 PHP_HTTP_CLIENT_ME(getObservers, ZEND_ACC_PUBLIC)
231 PHP_HTTP_CLIENT_ME(notify, ZEND_ACC_PUBLIC)
232 PHP_HTTP_CLIENT_ME(attach, ZEND_ACC_PUBLIC)
233 PHP_HTTP_CLIENT_ME(detach, ZEND_ACC_PUBLIC)
234 PHP_HTTP_CLIENT_ME(getProgress, ZEND_ACC_PUBLIC)
235 PHP_HTTP_CLIENT_ME(getTransferInfo, ZEND_ACC_PUBLIC)
236
237 PHP_HTTP_CLIENT_ME(setOptions, ZEND_ACC_PUBLIC)
238 PHP_HTTP_CLIENT_ME(getOptions, ZEND_ACC_PUBLIC)
239 PHP_HTTP_CLIENT_ME(setSslOptions, ZEND_ACC_PUBLIC)
240 PHP_HTTP_CLIENT_ME(getSslOptions, ZEND_ACC_PUBLIC)
241 PHP_HTTP_CLIENT_ME(addSslOptions, ZEND_ACC_PUBLIC)
242
243 PHP_HTTP_CLIENT_ME(addCookies, ZEND_ACC_PUBLIC)
244 PHP_HTTP_CLIENT_ME(getCookies, ZEND_ACC_PUBLIC)
245 PHP_HTTP_CLIENT_ME(setCookies, ZEND_ACC_PUBLIC)
246
247 PHP_HTTP_CLIENT_ME(enableCookies, ZEND_ACC_PUBLIC)
248 PHP_HTTP_CLIENT_ME(resetCookies, ZEND_ACC_PUBLIC)
249 PHP_HTTP_CLIENT_ME(flushCookies, ZEND_ACC_PUBLIC)
250
251 PHP_HTTP_CLIENT_ME(setRequest, ZEND_ACC_PUBLIC)
252 PHP_HTTP_CLIENT_ME(getRequest, ZEND_ACC_PUBLIC)
253
254 PHP_HTTP_CLIENT_ME(getResponseMessage, ZEND_ACC_PUBLIC)
255 PHP_HTTP_CLIENT_ME(getRequestMessage, ZEND_ACC_PUBLIC)
256 PHP_HTTP_CLIENT_ME(getHistory, ZEND_ACC_PUBLIC)
257 PHP_HTTP_CLIENT_ME(clearHistory, ZEND_ACC_PUBLIC)
258
259 PHP_HTTP_CLIENT_ME(getResponseMessageClass, ZEND_ACC_PUBLIC)
260 PHP_HTTP_CLIENT_ME(setResponseMessageClass, ZEND_ACC_PUBLIC)
261
262 PHP_HTTP_CLIENT_ME(request, ZEND_ACC_PUBLIC)
263
264 EMPTY_FUNCTION_ENTRY
265 };
266
267 static zend_object_handlers php_http_client_object_handlers;
268
269 zend_object_handlers *php_http_client_get_object_handlers(void)
270 {
271 return &php_http_client_object_handlers;
272 }
273
274 static php_http_client_ops_t php_http_client_user_ops = {
275 NULL,
276 NULL,
277 NULL,
278 NULL,
279 NULL,
280 NULL,
281 NULL,
282 NULL,
283 (php_http_new_t) php_http_client_object_new_ex,
284 php_http_client_get_class_entry
285 };
286
287 zend_object_value php_http_client_object_new(zend_class_entry *ce TSRMLS_DC)
288 {
289 return php_http_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
290 }
291
292 zend_object_value php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC)
293 {
294 zend_object_value ov;
295 php_http_client_object_t *o;
296
297 o = ecalloc(1, sizeof(*o));
298 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
299 #if PHP_VERSION_ID < 50339
300 zend_hash_copy(((zend_object *) o)->properties, &(ce->default_properties), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval*));
301 #else
302 object_properties_init((zend_object *) o, ce);
303 #endif
304 ov.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC);
305 ov.handlers = &php_http_client_object_handlers;
306
307 if (!(o->client = r)) {
308 o->client = php_http_client_init(NULL, &php_http_client_user_ops, NULL, &ov TSRMLS_CC);
309 }
310
311 if (ptr) {
312 *ptr = o;
313 }
314
315 return ov;
316 }
317
318 zend_object_value php_http_client_object_clone(zval *this_ptr TSRMLS_DC)
319 {
320 zend_object_value new_ov;
321 php_http_client_object_t *new_obj, *old_obj = zend_object_store_get_object(this_ptr TSRMLS_CC);
322
323 new_ov = php_http_client_object_new_ex(old_obj->zo.ce, php_http_client_copy(old_obj->client, NULL), &new_obj TSRMLS_CC);
324 zend_objects_clone_members(&new_obj->zo, new_ov, &old_obj->zo, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
325
326 return new_ov;
327 }
328
329 void php_http_client_object_free(void *object TSRMLS_DC)
330 {
331 php_http_client_object_t *o = (php_http_client_object_t *) object;
332
333 php_http_client_free(&o->client);
334 zend_object_std_dtor((zend_object *) o TSRMLS_CC);
335 efree(o);
336 }
337
338 static inline zend_object_value php_http_client_object_message(zval *this_ptr, php_http_message_t *msg TSRMLS_DC)
339 {
340 zend_object_value ov;
341 zval *zcn = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessageClass"), 0 TSRMLS_CC);
342 zend_class_entry *class_entry;
343
344 if (Z_STRLEN_P(zcn)
345 && (class_entry = zend_fetch_class(Z_STRVAL_P(zcn), Z_STRLEN_P(zcn), 0 TSRMLS_CC))
346 && (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_message_object_new_ex, php_http_client_response_get_class_entry(), msg, NULL TSRMLS_CC))) {
347 return ov;
348 } else {
349 return php_http_message_object_new_ex(php_http_client_response_get_class_entry(), msg, NULL TSRMLS_CC);
350 }
351 }
352
353 STATUS php_http_client_object_handle_request(zval *zclient, zval **zreq TSRMLS_DC)
354 {
355 php_http_client_object_t *obj = zend_object_store_get_object(zclient TSRMLS_CC);
356 php_http_client_progress_t *progress;
357 zval *zoptions;
358
359 /* do we have a valid request? */
360 if (*zreq) {
361 /* remember the request */
362 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("request"), *zreq TSRMLS_CC);
363 } else {
364 /* maybe a request is already set */
365 *zreq = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("request"), 0 TSRMLS_CC);
366
367 if (Z_TYPE_PP(zreq) != IS_OBJECT || !instanceof_function(Z_OBJCE_PP(zreq), php_http_client_request_get_class_entry() TSRMLS_CC)) {
368 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "The client does not have a valid request set");
369 return FAILURE;
370 }
371 }
372
373 /* reset request handle */
374 php_http_client_reset(obj->client);
375
376 /* reset transfer info */
377 zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("transferInfo") TSRMLS_CC);
378
379 /* set client options */
380 zoptions = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("options"), 0 TSRMLS_CC);
381 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_SETTINGS, Z_ARRVAL_P(zoptions));
382 /* set request options */
383 zoptions = zend_read_property(php_http_client_request_get_class_entry(), *zreq, ZEND_STRL("options"), 0 TSRMLS_CC);
384 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_SETTINGS, Z_ARRVAL_P(zoptions));
385
386 /* set progress callback */
387 if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) {
388 if (!progress->callback) {
389 php_http_client_progress_callback_t *callback = emalloc(sizeof(*callback));
390
391 callback->type = PHP_HTTP_CLIENT_PROGRESS_CALLBACK_USER;
392 callback->pass_state = 0;
393 MAKE_STD_ZVAL(callback->func.user);
394 array_init(callback->func.user);
395 Z_ADDREF_P(zclient);
396 add_next_index_zval(callback->func.user, zclient);
397 add_next_index_stringl(callback->func.user, ZEND_STRL("notify"), 1);
398
399 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK, callback);
400 }
401 progress->state.info = "start";
402 php_http_client_progress_notify(progress TSRMLS_CC);
403 progress->state.started = 1;
404 }
405
406 return SUCCESS;
407 }
408
409
410 STATUS php_http_client_object_handle_response(zval *zclient TSRMLS_DC)
411 {
412 php_http_client_object_t *obj = zend_object_store_get_object(zclient TSRMLS_CC);
413 php_http_client_progress_t *progress;
414 php_http_message_t *msg;
415 zval *info;
416
417 /* always fetch info */
418 MAKE_STD_ZVAL(info);
419 array_init(info);
420 php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, Z_ARRVAL_P(info));
421 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("transferInfo"), info TSRMLS_CC);
422 zval_ptr_dtor(&info);
423
424 if ((msg = obj->client->response.message)) {
425 if (i_zend_is_true(zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
426 zval *new_hist, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0 TSRMLS_CC);
427 php_http_message_t *zipped = php_http_message_zip(obj->client->response.message, obj->client->request.message);
428 zend_object_value ov = php_http_client_object_message(zclient, zipped TSRMLS_CC);
429
430 MAKE_STD_ZVAL(new_hist);
431 ZVAL_OBJVAL(new_hist, ov, 0);
432
433 if (Z_TYPE_P(old_hist) == IS_OBJECT) {
434 php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC);
435 }
436
437 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), new_hist TSRMLS_CC);
438 zval_ptr_dtor(&new_hist);
439 }
440
441 /* update response info */
442 if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, msg)) {
443 zval *message;
444
445 MAKE_STD_ZVAL(message);
446 ZVAL_OBJVAL(message, php_http_client_object_message(zclient, msg TSRMLS_CC), 0);
447 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage"), message TSRMLS_CC);
448 zval_ptr_dtor(&message);
449
450 obj->client->response.message = php_http_message_init(NULL, 0 TSRMLS_CC);
451 } else {
452 zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage") TSRMLS_CC);
453 }
454 } else {
455 zend_update_property_null(php_http_client_class_entry, zclient, ZEND_STRL("responseMessage") TSRMLS_CC);
456 }
457
458 if ((msg = obj->client->request.message)) {
459 if (PHP_HTTP_MESSAGE_TYPE(REQUEST, msg)) {
460 zval *message;
461
462 /* update the actual request message */
463 MAKE_STD_ZVAL(message);
464 ZVAL_OBJVAL(message, php_http_message_object_new_ex(php_http_message_get_class_entry(), msg, NULL TSRMLS_CC), 0);
465 zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("requestMessage"), message TSRMLS_CC);
466 zval_ptr_dtor(&message);
467 obj->client->request.message = php_http_message_init(NULL, 0 TSRMLS_CC);
468 }
469 }
470
471 if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) {
472 progress->state.info = "finished";
473 progress->state.finished = 1;
474 php_http_client_progress_notify(progress TSRMLS_CC);
475 }
476 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK, NULL);
477
478 return SUCCESS;
479 }
480
481 void php_http_client_options_set(zval *this_ptr, zval *opts TSRMLS_DC)
482 {
483 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
484 HashPosition pos;
485 zval *new_opts;
486 zend_class_entry *this_ce = Z_OBJCE_P(getThis());
487 zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry TSRMLS_CC);
488
489 MAKE_STD_ZVAL(new_opts);
490 array_init(new_opts);
491
492 if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
493 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
494 zval_ptr_dtor(&new_opts);
495 } else {
496 zval *old_opts, *add_opts, **opt;
497
498 MAKE_STD_ZVAL(add_opts);
499 array_init(add_opts);
500 /* some options need extra attention -- thus cannot use array_merge() directly */
501 FOREACH_KEYVAL(pos, opts, key, opt) {
502 if (key.type == HASH_KEY_IS_STRING) {
503 #define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
504 if (Z_TYPE_PP(opt) == IS_ARRAY && (KEYMATCH(key, "ssl") || KEYMATCH(key, "cookies"))) {
505 php_http_client_options_set_subr(getThis(), key.str, key.len, *opt, 0 TSRMLS_CC);
506 } else if (is_client && (KEYMATCH(key, "recordHistory") || KEYMATCH(key, "responseMessageClass"))) {
507 zend_update_property(this_ce, getThis(), key.str, key.len-1, *opt TSRMLS_CC);
508 } else if (Z_TYPE_PP(opt) == IS_NULL) {
509 old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
510 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
511 zend_symtable_del(Z_ARRVAL_P(old_opts), key.str, key.len);
512 }
513 } else {
514 Z_ADDREF_P(*opt);
515 add_assoc_zval_ex(add_opts, key.str, key.len, *opt);
516 }
517 }
518 }
519
520 old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
521 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
522 array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
523 }
524 array_join(Z_ARRVAL_P(add_opts), Z_ARRVAL_P(new_opts), 0, 0);
525 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
526 zval_ptr_dtor(&new_opts);
527 zval_ptr_dtor(&add_opts);
528 }
529 }
530
531 void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite TSRMLS_DC)
532 {
533 if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
534 zend_class_entry *this_ce = Z_OBJCE_P(getThis());
535 zval *old_opts, *new_opts, **entry = NULL;
536
537 MAKE_STD_ZVAL(new_opts);
538 array_init(new_opts);
539 old_opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
540 if (Z_TYPE_P(old_opts) == IS_ARRAY) {
541 array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL_P(new_opts));
542 }
543
544 if (overwrite) {
545 if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
546 Z_ADDREF_P(opts);
547 zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
548 } else {
549 zend_symtable_del(Z_ARRVAL_P(new_opts), key, len);
550 }
551 } else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
552 if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(new_opts), key, len, (void *) &entry)) {
553 array_join(Z_ARRVAL_P(opts), Z_ARRVAL_PP(entry), 0, 0);
554 } else {
555 Z_ADDREF_P(opts);
556 zend_symtable_update(Z_ARRVAL_P(new_opts), key, len, (void *) &opts, sizeof(zval *), NULL);
557 }
558 }
559
560 zend_update_property(this_ce, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC);
561 zval_ptr_dtor(&new_opts);
562 }
563 }
564
565 void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value TSRMLS_DC)
566 {
567 zend_class_entry *this_ce = Z_OBJCE_P(getThis());
568 zval **options, *opts = zend_read_property(this_ce, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC);
569
570 if ((Z_TYPE_P(opts) == IS_ARRAY) && (SUCCESS == zend_symtable_find(Z_ARRVAL_P(opts), key, len, (void *) &options))) {
571 RETVAL_ZVAL(*options, 1, 0);
572 }
573 }
574
575 PHP_METHOD(HttpClient, __construct)
576 {
577 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
578 zval *os, *opts = NULL;
579
580 MAKE_STD_ZVAL(os);
581 object_init_ex(os, spl_ce_SplObjectStorage);
582 zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), os TSRMLS_CC);
583 zval_ptr_dtor(&os);
584
585 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
586 php_http_client_options_set(getThis(), opts TSRMLS_CC);
587 }
588
589 } end_error_handling();
590 }
591
592 PHP_METHOD(HttpClient, getObservers)
593 {
594 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
595 if (SUCCESS == zend_parse_parameters_none()) {
596 RETVAL_PROP(php_http_client_class_entry, "observers");
597 }
598 } end_error_handling();
599 }
600
601 static int notify(zend_object_iterator *iter, void *puser TSRMLS_DC)
602 {
603 zval **observer = NULL;
604
605 iter->funcs->get_current_data(iter, &observer TSRMLS_CC);
606 if (observer) {
607 zval *retval;
608
609 zend_call_method_with_1_params(observer, NULL, NULL, "update", &retval, puser);
610 zval_ptr_dtor(&retval);
611 return SUCCESS;
612 }
613 return FAILURE;
614 }
615
616 PHP_METHOD(HttpClient, notify)
617 {
618 if (SUCCESS == zend_parse_parameters_none()) {
619 zval *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
620
621 if (Z_TYPE_P(observers) == IS_OBJECT) {
622 Z_ADDREF_P(getThis());
623 spl_iterator_apply(observers, notify, getThis() TSRMLS_CC);
624 zval_ptr_dtor(&getThis());
625 }
626 }
627
628 RETVAL_ZVAL(getThis(), 1, 0);
629 }
630
631 PHP_METHOD(HttpClient, attach)
632 {
633 zval *observer;
634
635 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) {
636 zval *retval, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
637 zend_call_method_with_1_params(&observers, NULL, NULL, "attach", &retval, observer);
638 zval_ptr_dtor(&retval);
639 }
640
641 RETVAL_ZVAL(getThis(), 1, 0);
642 }
643
644 PHP_METHOD(HttpClient, detach)
645 {
646 zval *observer;
647
648 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &observer, spl_ce_SplObserver)) {
649 zval *retval, *observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0 TSRMLS_CC);
650 zend_call_method_with_1_params(&observers, NULL, NULL, "detach", &retval, observer);
651 zval_ptr_dtor(&retval);
652 }
653
654 RETVAL_ZVAL(getThis(), 1, 0);
655 }
656
657 PHP_METHOD(HttpClient, getProgress)
658 {
659 if (SUCCESS == zend_parse_parameters_none()) {
660 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
661 php_http_client_progress_t *progress = NULL;
662
663 if (SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, &progress)) {
664 object_init(return_value);
665 add_property_bool(return_value, "started", progress->state.started);
666 add_property_bool(return_value, "finished", progress->state.finished);
667 add_property_string(return_value, "info", STR_PTR(progress->state.info), 1);
668 add_property_double(return_value, "dltotal", progress->state.dl.total);
669 add_property_double(return_value, "dlnow", progress->state.dl.now);
670 add_property_double(return_value, "ultotal", progress->state.ul.total);
671 add_property_double(return_value, "ulnow", progress->state.ul.now);
672 }
673 }
674 }
675
676 PHP_METHOD(HttpClient, getTransferInfo)
677 {
678 char *info_name = NULL;
679 int info_len = 0;
680
681 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s", &info_name, &info_len)) {
682 zval **infop, *temp = NULL, *info = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("transferInfo"), 0 TSRMLS_CC);
683
684 /* request completed? */
685 if (Z_TYPE_P(info) != IS_ARRAY) {
686 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
687
688 MAKE_STD_ZVAL(temp);
689 array_init(temp);
690 php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, Z_ARRVAL_P(temp));
691 info = temp;
692 }
693
694 if (info_len && info_name) {
695 if (SUCCESS == zend_symtable_find(Z_ARRVAL_P(info), php_http_pretty_key(info_name, info_len, 0, 0), info_len + 1, (void *) &infop)) {
696 RETVAL_ZVAL(*infop, 1, 0);
697 } else {
698 php_http_error(HE_NOTICE, PHP_HTTP_E_INVALID_PARAM, "Could not find transfer info named %s", info_name);
699 RETVAL_FALSE;
700 }
701 } else {
702 RETVAL_ZVAL(info, 1, 0);
703 }
704
705 if (temp) {
706 zval_ptr_dtor(&temp);
707 }
708 return;
709 }
710 RETURN_FALSE;
711 }
712
713 PHP_METHOD(HttpClient, setOptions)
714 {
715 zval *opts = NULL;
716
717 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
718 php_http_client_options_set(getThis(), opts TSRMLS_CC);
719
720 RETVAL_ZVAL(getThis(), 1, 0);
721 }
722 }
723
724 PHP_METHOD(HttpClient, getOptions)
725 {
726 if (SUCCESS == zend_parse_parameters_none()) {
727 RETURN_PROP(php_http_client_class_entry, "options");
728 }
729 RETURN_FALSE;
730 }
731
732 PHP_METHOD(HttpClient, setSslOptions)
733 {
734 zval *opts = NULL;
735
736 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
737 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 1 TSRMLS_CC);
738
739 RETVAL_ZVAL(getThis(), 1, 0);
740 }
741 }
742
743 PHP_METHOD(HttpClient, addSslOptions)
744 {
745 zval *opts = NULL;
746
747 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
748 php_http_client_options_set_subr(getThis(), ZEND_STRS("ssl"), opts, 0 TSRMLS_CC);
749
750 RETVAL_ZVAL(getThis(), 1, 0);
751 }
752 }
753
754 PHP_METHOD(HttpClient, getSslOptions)
755 {
756 if (SUCCESS == zend_parse_parameters_none()) {
757 php_http_client_options_get_subr(getThis(), ZEND_STRS("ssl"), return_value TSRMLS_CC);
758 }
759 }
760
761 PHP_METHOD(HttpClient, setCookies)
762 {
763 zval *opts = NULL;
764
765 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
766 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 1 TSRMLS_CC);
767
768 RETVAL_ZVAL(getThis(), 1, 0);
769 }
770 }
771
772 PHP_METHOD(HttpClient, addCookies)
773 {
774 zval *opts = NULL;
775
776 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!/", &opts)) {
777 php_http_client_options_set_subr(getThis(), ZEND_STRS("cookies"), opts, 0 TSRMLS_CC);
778
779 RETVAL_ZVAL(getThis(), 1, 0);
780 }
781 }
782
783 PHP_METHOD(HttpClient, getCookies)
784 {
785 if (SUCCESS == zend_parse_parameters_none()) {
786 php_http_client_options_get_subr(getThis(), ZEND_STRS("cookies"), return_value TSRMLS_CC);
787 }
788 }
789
790 PHP_METHOD(HttpClient, enableCookies)
791 {
792 if (SUCCESS == zend_parse_parameters_none()){
793 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
794
795 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE, NULL);
796 }
797 RETVAL_ZVAL(getThis(), 1, 0);
798 }
799
800 PHP_METHOD(HttpClient, resetCookies)
801 {
802 zend_bool session_only = 0;
803
804 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &session_only)) {
805 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
806 if (session_only) {
807 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION, NULL);
808 } else {
809 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_RESET, NULL);
810 }
811 }
812 RETVAL_ZVAL(getThis(), 1, 0);
813 }
814
815 PHP_METHOD(HttpClient, flushCookies)
816 {
817 if (SUCCESS == zend_parse_parameters_none()) {
818 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
819
820 php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH, NULL);
821 }
822 RETVAL_ZVAL(getThis(), 1, 0);
823 }
824
825 PHP_METHOD(HttpClient, getResponseMessage)
826 {
827 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
828 if (SUCCESS == zend_parse_parameters_none()) {
829 zval *message = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC);
830
831 if (Z_TYPE_P(message) == IS_OBJECT) {
832 RETVAL_OBJECT(message, 1);
833 } else {
834 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpClient does not contain a response message");
835 }
836 }
837 } end_error_handling();
838 }
839
840 PHP_METHOD(HttpClient, getRequestMessage)
841 {
842 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
843 if (SUCCESS == zend_parse_parameters_none()) {
844 zval *message = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("requestMessage"), 0 TSRMLS_CC);
845
846 if (Z_TYPE_P(message) == IS_OBJECT) {
847 RETVAL_OBJECT(message, 1);
848 } else {
849 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpClient does not contain a request message");
850 }
851 }
852 } end_error_handling();
853 }
854
855 PHP_METHOD(HttpClient, getHistory)
856 {
857 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
858 if (SUCCESS == zend_parse_parameters_none()) {
859 zval *hist = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
860
861 if (Z_TYPE_P(hist) == IS_OBJECT) {
862 RETVAL_OBJECT(hist, 1);
863 } else {
864 php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "The history is empty");
865 }
866 }
867 } end_error_handling();
868 }
869
870 PHP_METHOD(HttpClient, clearHistory)
871 {
872 if (SUCCESS == zend_parse_parameters_none()) {
873 zend_update_property_null(php_http_client_class_entry, getThis(), ZEND_STRL("history") TSRMLS_CC);
874 }
875 RETVAL_ZVAL(getThis(), 1, 0);
876 }
877
878 PHP_METHOD(HttpClient, getResponseMessageClass)
879 {
880 if (SUCCESS == zend_parse_parameters_none()) {
881 RETURN_PROP(php_http_client_class_entry, "responseMessageClass");
882 }
883 RETURN_FALSE;
884 }
885
886 PHP_METHOD(HttpClient, setResponseMessageClass)
887 {
888 char *cn;
889 int cl;
890
891 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &cn, &cl)) {
892 zend_update_property_stringl(php_http_client_class_entry, getThis(), ZEND_STRL("responseMessageClass"), cn, cl TSRMLS_CC);
893 }
894 RETVAL_ZVAL(getThis(), 1, 0);
895 }
896
897 PHP_METHOD(HttpClient, setRequest)
898 {
899 zval *zreq = NULL;
900
901 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &zreq, php_http_client_request_get_class_entry())) {
902 zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("request"), zreq TSRMLS_CC);
903 }
904 RETURN_ZVAL(getThis(), 1, 0);
905 }
906
907 PHP_METHOD(HttpClient, getRequest)
908 {
909 if (SUCCESS == zend_parse_parameters_none()) {
910 RETURN_PROP(php_http_client_class_entry, "request");
911 }
912 }
913
914 PHP_METHOD(HttpClient, request)
915 {
916 char *meth_str, *url_str;
917 int meth_len, url_len;
918 zval *zheader, *zbody, *zoptions;
919
920 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
921 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|a!z!a!/", &meth_str, &meth_len, &url_str, &url_len, &zheader, &zbody, &zoptions)) {
922 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
923 php_http_message_object_t *msg_obj;
924 zend_object_value ov;
925 zval *req, *res = NULL;
926
927 php_http_new(&ov, php_http_client_request_get_class_entry(), (php_http_new_t) php_http_message_object_new_ex, NULL, NULL, (void *) &msg_obj TSRMLS_CC);
928 MAKE_STD_ZVAL(req);
929 ZVAL_OBJVAL(req, ov, 0);
930
931 msg_obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST TSRMLS_CC);
932 PHP_HTTP_INFO(msg_obj->message).request.url = estrndup(url_str, url_len);
933 PHP_HTTP_INFO(msg_obj->message).request.method = estrndup(meth_str, meth_len);
934
935 if (zheader) {
936 array_copy(Z_ARRVAL_P(zheader), &msg_obj->message->hdrs);
937 }
938
939 if (zbody) {
940 php_http_message_object_set_body(msg_obj, zbody TSRMLS_CC);
941 }
942
943 if (zoptions) {
944 php_http_client_options_set(req, zoptions TSRMLS_CC);
945 }
946
947 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL, "send", &res, req);
948 RETVAL_ZVAL(res, 0, 1);
949 zval_ptr_dtor(&req);
950 }
951 } end_error_handling();
952 }
953
954 PHP_METHOD(HttpClient, send)
955 {
956 zval *zreq = NULL;
957
958 RETVAL_FALSE;
959
960 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
961 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|O!", &zreq, php_http_client_request_get_class_entry())) {
962 if (SUCCESS == php_http_client_object_handle_request(getThis(), &zreq TSRMLS_CC)) {
963 php_http_client_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC);
964 php_http_message_object_t *req = zend_object_store_get_object(zreq TSRMLS_CC);
965
966 php_http_client_exec(obj->client, req->message);
967
968 if (SUCCESS == php_http_client_object_handle_response(getThis() TSRMLS_CC)) {
969 RETVAL_PROP(php_http_client_class_entry, "responseMessage");
970 } else {
971 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to handle response");
972 }
973 } else {
974 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Failed to handle request");
975 }
976 }
977 } end_error_handling();
978 }
979
980 PHP_MINIT_FUNCTION(http_client)
981 {
982 PHP_HTTP_REGISTER_CLASS(http\\Client, AbstractClient, http_client, php_http_object_get_class_entry(), ZEND_ACC_ABSTRACT);
983 php_http_client_class_entry->create_object = php_http_client_object_new;
984 memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
985 php_http_client_object_handlers.clone_obj = php_http_client_object_clone;
986
987 zend_class_implements(php_http_client_class_entry TSRMLS_CC, 2, spl_ce_SplSubject, php_http_client_interface_get_class_entry());
988
989 zend_declare_property_string(php_http_client_class_entry, ZEND_STRL("responseMessageClass"), "", ZEND_ACC_PRIVATE TSRMLS_CC);
990 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE TSRMLS_CC);
991 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("transferInfo"), ZEND_ACC_PRIVATE TSRMLS_CC);
992 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("responseMessage"), ZEND_ACC_PRIVATE TSRMLS_CC);
993 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("requestMessage"), ZEND_ACC_PRIVATE TSRMLS_CC);
994 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PRIVATE TSRMLS_CC);
995
996 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED TSRMLS_CC);
997 zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED TSRMLS_CC);
998
999 zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC);
1000
1001 return SUCCESS;
1002 }
1003
1004 /*
1005 * Local variables:
1006 * tab-width: 4
1007 * c-basic-offset: 4
1008 * End:
1009 * vim600: noet sw=4 ts=4 fdm=marker
1010 * vim<600: noet sw=4 ts=4
1011 */
1012