extesion deps
[m6w6/ext-http] / php_http_client_factory.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 /*
18 * array of name => php_http_client_factory_driver_t*
19 */
20 static HashTable php_http_client_factory_drivers;
21
22 PHP_HTTP_API STATUS php_http_client_factory_add_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver)
23 {
24 return zend_hash_add(&php_http_client_factory_drivers, name_str, name_len + 1, (void *) driver, sizeof(php_http_client_factory_driver_t), NULL);
25 }
26
27 PHP_HTTP_API STATUS php_http_client_factory_get_driver(const char *name_str, size_t name_len, php_http_client_factory_driver_t *driver)
28 {
29 php_http_client_factory_driver_t *tmp;
30
31 if (SUCCESS == zend_hash_find(&php_http_client_factory_drivers, name_str, name_len + 1, (void *) &tmp)) {
32 *driver = *tmp;
33 return SUCCESS;
34 }
35 return FAILURE;
36 }
37
38 static zend_class_entry *php_http_client_factory_find_class_entry(zval *this_ptr, const char *for_str, size_t for_len TSRMLS_DC)
39 {
40 /* stupid non-const api */
41 zval *cn = zend_read_property(Z_OBJCE_P(getThis()), getThis(), for_str, for_len, 0 TSRMLS_CC);
42
43 if (Z_TYPE_P(cn) == IS_STRING && Z_STRLEN_P(cn)) {
44 return zend_fetch_class(Z_STRVAL_P(cn), Z_STRLEN_P(cn), 0 TSRMLS_CC);
45 }
46
47 return NULL;
48 }
49
50 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientFactory, method, 0, req_args)
51 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientFactory, method, 0)
52 #define PHP_HTTP_REQUEST_FACTORY_ME(method, visibility) PHP_ME(HttpClientFactory, method, PHP_HTTP_ARGS(HttpClientFactory, method), visibility)
53 #define PHP_HTTP_REQUEST_FACTORY_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpClientFactory, method))
54 #define PHP_HTTP_REQUEST_FACTORY_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpClientFactory_##al), PHP_HTTP_ARGS(HttpClientFactory, al), vis)
55
56 PHP_HTTP_BEGIN_ARGS(__construct, 0)
57 PHP_HTTP_ARG_VAL(options, 0)
58 PHP_HTTP_END_ARGS;
59 PHP_HTTP_BEGIN_ARGS(createClient, 0)
60 PHP_HTTP_ARG_ARR(options, 1, 0)
61 PHP_HTTP_END_ARGS;
62 PHP_HTTP_BEGIN_ARGS(createPool, 0)
63 PHP_HTTP_ARG_OBJ(http\\Client, client1, 1)
64 PHP_HTTP_ARG_OBJ(http\\Client, client2, 1)
65 PHP_HTTP_ARG_OBJ(http\\Client, clientN, 1)
66 PHP_HTTP_END_ARGS;
67 PHP_HTTP_BEGIN_ARGS(createDataShare, 0)
68 PHP_HTTP_ARG_OBJ(http\\Client, client1, 1)
69 PHP_HTTP_ARG_OBJ(http\\Client, client2, 1)
70 PHP_HTTP_ARG_OBJ(http\\Client, clientN, 1)
71 PHP_HTTP_END_ARGS;
72 PHP_HTTP_EMPTY_ARGS(getDriver);
73 PHP_HTTP_EMPTY_ARGS(getAvailableDrivers);
74
75 static zend_class_entry *php_http_client_factory_class_entry;
76
77 zend_class_entry *php_http_client_factory_get_class_entry(void)
78 {
79 return php_http_client_factory_class_entry;
80 }
81
82 static zend_function_entry php_http_client_factory_method_entry[] = {
83 PHP_HTTP_REQUEST_FACTORY_ME(__construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
84 PHP_HTTP_REQUEST_FACTORY_ME(createClient, ZEND_ACC_PUBLIC)
85 PHP_HTTP_REQUEST_FACTORY_ME(createPool, ZEND_ACC_PUBLIC)
86 PHP_HTTP_REQUEST_FACTORY_ME(createDataShare, ZEND_ACC_PUBLIC)
87 PHP_HTTP_REQUEST_FACTORY_ME(getDriver, ZEND_ACC_PUBLIC)
88 PHP_HTTP_REQUEST_FACTORY_ME(getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
89
90 EMPTY_FUNCTION_ENTRY
91 };
92
93 PHP_METHOD(HttpClientFactory, __construct)
94 {
95 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
96 HashTable *options = NULL;
97
98 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|h", &options)) {
99 if (options) {
100 zval **val;
101 HashPosition pos;
102 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
103
104 FOREACH_HASH_KEYVAL(pos, options, key, val) {
105 if (key.type == HASH_KEY_IS_STRING) {
106 zval *newval = php_http_zsep(1, Z_TYPE_PP(val), *val);
107 zend_update_property(php_http_client_factory_class_entry, getThis(), key.str, key.len - 1, newval TSRMLS_CC);
108 zval_ptr_dtor(&newval);
109 }
110 }
111 }
112 }
113 } end_error_handling();
114 }
115
116 PHP_METHOD(HttpClientFactory, createClient)
117 {
118 zval *options = NULL;
119
120 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
121 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &options)) {
122 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
123 zval *zdriver;
124 zend_object_value ov;
125 zend_class_entry *class_entry = NULL;
126 php_http_client_t *req = NULL;
127 php_http_client_factory_driver_t driver;
128
129 zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC);
130
131 if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_ops) {
132 zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC));
133 php_resource_factory_t *rf = NULL;
134
135 if (Z_STRLEN_P(phi)) {
136 char *name_str;
137 size_t name_len;
138 php_persistent_handle_factory_t *pf;
139
140 name_len = spprintf(&name_str, 0, "http_client.%s", Z_STRVAL_P(zdriver));
141
142 if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) {
143 rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon);
144 }
145
146 efree(name_str);
147 }
148
149 req = php_http_client_init(NULL, driver.client_ops, rf, NULL TSRMLS_CC);
150 if (req) {
151 if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientClass") TSRMLS_CC))) {
152 class_entry = driver.client_ops->class_entry();
153 }
154
155 if (SUCCESS == php_http_new(&ov, class_entry, driver.client_ops->create_object, driver.client_ops->class_entry(), req, NULL TSRMLS_CC)) {
156 ZVAL_OBJVAL(return_value, ov, 0);
157 zend_call_method(&return_value, Z_OBJCE_P(return_value), NULL, ZEND_STRL("__construct"), NULL, !!options, options, NULL TSRMLS_CC);
158 } else {
159 php_http_client_free(&req);
160 }
161 }
162
163 zval_ptr_dtor(&phi);
164 } else {
165 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "clients are not supported by this driver");
166 }
167 } end_error_handling();
168 }
169 } end_error_handling();
170 }
171
172 PHP_METHOD(HttpClientFactory, createPool)
173 {
174 int argc = 0;
175 zval ***argv = NULL;
176
177 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
178 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &argv, &argc)) {
179 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
180 int i;
181 zval *zdriver;
182 zend_object_value ov;
183 zend_class_entry *class_entry = NULL;
184 php_http_client_pool_t *pool = NULL;
185 php_http_client_factory_driver_t driver;
186
187 zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC);
188 if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_pool_ops) {
189 zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC));
190 php_resource_factory_t *rf = NULL;
191
192 if (Z_STRLEN_P(phi)) {
193 char *name_str;
194 size_t name_len;
195 php_persistent_handle_factory_t *pf;
196
197 name_len = spprintf(&name_str, 0, "http_client_pool.%s", Z_STRVAL_P(zdriver));
198
199 if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) {
200 rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon);
201 }
202
203 efree(name_str);
204 }
205
206 pool = php_http_client_pool_init(NULL, driver.client_pool_ops, rf, NULL TSRMLS_CC);
207 if (pool) {
208 if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientPoolClass") TSRMLS_CC))) {
209 class_entry = driver.client_pool_ops->class_entry();
210 }
211
212 if (SUCCESS == php_http_new(&ov, class_entry, driver.client_pool_ops->create_object, driver.client_pool_ops->class_entry(), pool, NULL TSRMLS_CC)) {
213 ZVAL_OBJVAL(return_value, ov, 0);
214 for (i = 0; i < argc; ++i) {
215 if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), php_http_client_get_class_entry() TSRMLS_CC)) {
216 php_http_client_pool_attach(pool, *(argv[i]));
217 }
218 }
219 } else {
220 php_http_client_pool_free(&pool);
221 }
222 }
223
224 zval_ptr_dtor(&phi);
225 } else {
226 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "pools are not supported by this driver");
227 }
228 } end_error_handling();
229
230 if (argv) {
231 efree(argv);
232 }
233 }
234 } end_error_handling();
235 }
236
237 PHP_METHOD(HttpClientFactory, createDataShare)
238 {
239 int argc = 0;
240 zval ***argv = NULL;
241
242 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
243 if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &argv, &argc)) {
244 with_error_handling(EH_THROW, php_http_exception_get_class_entry()) {
245 int i;
246 zval *zdriver;
247 zend_object_value ov;
248 zend_class_entry *class_entry;
249 php_http_client_datashare_t *share = NULL;
250 php_http_client_factory_driver_t driver;
251
252 zdriver = zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC);
253 if ((IS_STRING == Z_TYPE_P(zdriver)) && (SUCCESS == php_http_client_factory_get_driver(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver), &driver)) && driver.client_datashare_ops) {
254 zval *phi = php_http_zsep(1, IS_STRING, zend_read_property(php_http_client_factory_class_entry, getThis(), ZEND_STRL("persistentHandleId"), 0 TSRMLS_CC));
255 php_resource_factory_t *rf = NULL;
256
257 if (Z_STRLEN_P(phi)) {
258 char *name_str;
259 size_t name_len;
260 php_persistent_handle_factory_t *pf;
261
262 name_len = spprintf(&name_str, 0, "http_client_datashare.%s", Z_STRVAL_P(zdriver));
263
264 if ((pf = php_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi), NULL, NULL TSRMLS_CC))) {
265 rf = php_resource_factory_init(NULL, php_persistent_handle_get_resource_factory_ops(), pf, (void (*)(void *)) php_persistent_handle_abandon);
266 }
267
268 efree(name_str);
269 }
270
271 share = php_http_client_datashare_init(NULL, driver.client_datashare_ops, rf, NULL TSRMLS_CC);
272 if (share) {
273 if (!(class_entry = php_http_client_factory_find_class_entry(getThis(), ZEND_STRL("clientDataShareClass") TSRMLS_CC))) {
274 class_entry = driver.client_datashare_ops->class_entry();
275 }
276
277 if (SUCCESS == php_http_new(&ov, class_entry, driver.client_datashare_ops->create_object, driver.client_datashare_ops->class_entry(), share, NULL TSRMLS_CC)) {
278 ZVAL_OBJVAL(return_value, ov, 0);
279 for (i = 0; i < argc; ++i) {
280 if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), php_http_client_get_class_entry() TSRMLS_CC)) {
281 php_http_client_datashare_attach(share, *(argv[i]));
282 }
283 }
284 } else {
285 php_http_client_datashare_free(&share);
286 }
287 }
288
289 zval_ptr_dtor(&phi);
290 } else {
291 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_FACTORY, "datashares are not supported by this driver");
292 }
293 } end_error_handling();
294 if (argv) {
295 efree(argv);
296 }
297 }
298 } end_error_handling();
299 }
300
301 PHP_METHOD(HttpClientFactory, getDriver)
302 {
303 if (SUCCESS == zend_parse_parameters_none()) {
304 RETURN_PROP(php_http_client_factory_class_entry, "driver");
305 }
306 RETURN_FALSE;
307 }
308
309 PHP_METHOD(HttpClientFactory, getAvailableDrivers)
310 {
311 if (SUCCESS == zend_parse_parameters_none()) {
312 HashPosition pos;
313 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
314
315 array_init(return_value);
316 FOREACH_HASH_KEY(pos, &php_http_client_factory_drivers, key) {
317 add_next_index_stringl(return_value, key.str, key.len - 1, 1);
318 }
319 return;
320 }
321 RETURN_FALSE;
322 }
323
324 PHP_MINIT_FUNCTION(http_client_factory)
325 {
326 zend_hash_init(&php_http_client_factory_drivers, 0, NULL, NULL, 1);
327
328 PHP_HTTP_REGISTER_CLASS(http\\Client, Factory, http_client_factory, php_http_object_get_class_entry(), 0);
329 php_http_client_factory_class_entry->create_object = php_http_client_factory_new;
330
331 zend_declare_property_stringl(php_http_client_factory_class_entry, ZEND_STRL("driver"), ZEND_STRL("curl"), ZEND_ACC_PROTECTED TSRMLS_CC);
332 zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("persistentHandleId"), ZEND_ACC_PROTECTED TSRMLS_CC);
333 zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientClass"), ZEND_ACC_PROTECTED TSRMLS_CC);
334 zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientPoolClass"), ZEND_ACC_PROTECTED TSRMLS_CC);
335 zend_declare_property_null(php_http_client_factory_class_entry, ZEND_STRL("clientDataShareClass"), ZEND_ACC_PROTECTED TSRMLS_CC);
336
337 return SUCCESS;
338 }
339
340 PHP_MSHUTDOWN_FUNCTION(http_client_factory)
341 {
342 zend_hash_destroy(&php_http_client_factory_drivers);
343
344 return SUCCESS;
345 }
346
347
348 /*
349 * Local variables:
350 * tab-width: 4
351 * c-basic-offset: 4
352 * End:
353 * vim600: noet sw=4 ts=4 fdm=marker
354 * vim<600: noet sw=4 ts=4
355 */
356