split off raphf
[m6w6/ext-http] / php_http_curl_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 /* resource_factory ops */
16
17 static void *php_http_curl_ctor(void *opaque, void *init_arg TSRMLS_DC)
18 {
19 void *ch;
20
21 if ((ch = curl_easy_init())) {
22 php_http_curl_client_get_storage(ch);
23 return ch;
24 }
25 return NULL;
26 }
27
28 static void *php_http_curl_copy(void *opaque, void *handle TSRMLS_DC)
29 {
30 void *ch;
31
32 if ((ch = curl_easy_duphandle(handle))) {
33 curl_easy_reset(ch);
34 php_http_curl_client_get_storage(ch);
35 return ch;
36 }
37 return NULL;
38 }
39
40 static void php_http_curl_dtor(void *opaque, void *handle TSRMLS_DC)
41 {
42 php_http_curl_client_storage_t *st = php_http_curl_client_get_storage(handle);
43
44 curl_easy_cleanup(handle);
45
46 if (st) {
47 if (st->url) {
48 pefree(st->url, 1);
49 }
50 if (st->cookiestore) {
51 pefree(st->cookiestore, 1);
52 }
53 pefree(st, 1);
54 }
55 }
56
57 /* callbacks */
58
59 static size_t php_http_curl_client_read_callback(void *data, size_t len, size_t n, void *ctx)
60 {
61 php_http_message_body_t *body = ctx;
62
63 if (body) {
64 TSRMLS_FETCH_FROM_CTX(body->ts);
65 return php_stream_read(php_http_message_body_stream(body), data, len * n);
66 }
67 return 0;
68 }
69
70 static int php_http_curl_client_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
71 {
72 php_http_client_t *h = ctx;
73 php_http_curl_client_t *curl = h->ctx;
74 TSRMLS_FETCH_FROM_CTX(h->ts);
75
76 curl->progress.state.dl.total = dltotal;
77 curl->progress.state.dl.now = dlnow;
78 curl->progress.state.ul.total = ultotal;
79 curl->progress.state.ul.now = ulnow;
80
81 php_http_client_progress_notify(&curl->progress TSRMLS_CC);
82
83 return 0;
84 }
85
86 static curlioerr php_http_curl_client_ioctl_callback(CURL *ch, curliocmd cmd, void *ctx)
87 {
88 php_http_message_body_t *body = ctx;
89
90 if (cmd != CURLIOCMD_RESTARTREAD) {
91 return CURLIOE_UNKNOWNCMD;
92 }
93
94 if (body) {
95 TSRMLS_FETCH_FROM_CTX(body->ts);
96
97 if (SUCCESS == php_stream_rewind(php_http_message_body_stream(body))) {
98 return CURLIOE_OK;
99 }
100 }
101
102 return CURLIOE_FAILRESTART;
103 }
104
105 static int php_http_curl_client_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
106 {
107 php_http_client_t *h = ctx;
108 php_http_curl_client_t *curl = h->ctx;
109 unsigned flags = 0;
110 TSRMLS_FETCH_FROM_CTX(h->ts);
111
112 /* catch progress */
113 switch (type) {
114 case CURLINFO_TEXT:
115 if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) {
116 curl->progress.state.info = "resolve";
117 } else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) {
118 curl->progress.state.info = "connect";
119 } else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) {
120 curl->progress.state.info = "connected";
121 } else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) {
122 curl->progress.state.info = "not disconnected";
123 } else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) {
124 curl->progress.state.info = "disconnected";
125 } else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) {
126 curl->progress.state.info = "redirect";
127 }
128 php_http_client_progress_notify(&curl->progress TSRMLS_CC);
129 break;
130 case CURLINFO_HEADER_OUT:
131 case CURLINFO_DATA_OUT:
132 case CURLINFO_SSL_DATA_OUT:
133 curl->progress.state.info = "send";
134 break;
135 case CURLINFO_HEADER_IN:
136 case CURLINFO_DATA_IN:
137 case CURLINFO_SSL_DATA_IN:
138 curl->progress.state.info = "receive";
139 break;
140 default:
141 break;
142 }
143 /* process data */
144 switch (type) {
145 case CURLINFO_HEADER_IN:
146 case CURLINFO_DATA_IN:
147 php_http_buffer_append(h->response.buffer, data, length);
148
149 if (curl->options.redirects) {
150 flags |= PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS;
151 }
152
153 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->response.parser, h->response.buffer, flags, &h->response.message)) {
154 return -1;
155 }
156 break;
157
158 case CURLINFO_HEADER_OUT:
159 case CURLINFO_DATA_OUT:
160 php_http_buffer_append(h->request.buffer, data, length);
161
162 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(h->request.parser, h->request.buffer, flags, &h->request.message)) {
163 return -1;
164 }
165 break;
166 default:
167 break;
168 }
169
170 #if 0
171 /* debug */
172 _dpf(type, data, length);
173 #endif
174
175 return 0;
176 }
177
178 static int php_http_curl_client_dummy_callback(char *data, size_t n, size_t l, void *s)
179 {
180 return n*l;
181 }
182
183 static STATUS get_info(CURL *ch, HashTable *info)
184 {
185 char *c;
186 long l;
187 double d;
188 struct curl_slist *s, *p;
189 zval *subarray, array;
190 INIT_PZVAL_ARRAY(&array, info);
191
192 /* BEGIN::CURLINFO */
193 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) {
194 add_assoc_string_ex(&array, "effective_url", sizeof("effective_url"), c ? c : "", 1);
195 }
196 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) {
197 add_assoc_long_ex(&array, "response_code", sizeof("response_code"), l);
198 }
199 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) {
200 add_assoc_double_ex(&array, "total_time", sizeof("total_time"), d);
201 }
202 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) {
203 add_assoc_double_ex(&array, "namelookup_time", sizeof("namelookup_time"), d);
204 }
205 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) {
206 add_assoc_double_ex(&array, "connect_time", sizeof("connect_time"), d);
207 }
208 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) {
209 add_assoc_double_ex(&array, "pretransfer_time", sizeof("pretransfer_time"), d);
210 }
211 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) {
212 add_assoc_double_ex(&array, "size_upload", sizeof("size_upload"), d);
213 }
214 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) {
215 add_assoc_double_ex(&array, "size_download", sizeof("size_download"), d);
216 }
217 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) {
218 add_assoc_double_ex(&array, "speed_download", sizeof("speed_download"), d);
219 }
220 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) {
221 add_assoc_double_ex(&array, "speed_upload", sizeof("speed_upload"), d);
222 }
223 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) {
224 add_assoc_long_ex(&array, "header_size", sizeof("header_size"), l);
225 }
226 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) {
227 add_assoc_long_ex(&array, "request_size", sizeof("request_size"), l);
228 }
229 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) {
230 add_assoc_long_ex(&array, "ssl_verifyresult", sizeof("ssl_verifyresult"), l);
231 }
232 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) {
233 add_assoc_long_ex(&array, "filetime", sizeof("filetime"), l);
234 }
235 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
236 add_assoc_double_ex(&array, "content_length_download", sizeof("content_length_download"), d);
237 }
238 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) {
239 add_assoc_double_ex(&array, "content_length_upload", sizeof("content_length_upload"), d);
240 }
241 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) {
242 add_assoc_double_ex(&array, "starttransfer_time", sizeof("starttransfer_time"), d);
243 }
244 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) {
245 add_assoc_string_ex(&array, "content_type", sizeof("content_type"), c ? c : "", 1);
246 }
247 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) {
248 add_assoc_double_ex(&array, "redirect_time", sizeof("redirect_time"), d);
249 }
250 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) {
251 add_assoc_long_ex(&array, "redirect_count", sizeof("redirect_count"), l);
252 }
253 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) {
254 add_assoc_long_ex(&array, "connect_code", sizeof("connect_code"), l);
255 }
256 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) {
257 add_assoc_long_ex(&array, "httpauth_avail", sizeof("httpauth_avail"), l);
258 }
259 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) {
260 add_assoc_long_ex(&array, "proxyauth_avail", sizeof("proxyauth_avail"), l);
261 }
262 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) {
263 add_assoc_long_ex(&array, "os_errno", sizeof("os_errno"), l);
264 }
265 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) {
266 add_assoc_long_ex(&array, "num_connects", sizeof("num_connects"), l);
267 }
268 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) {
269 MAKE_STD_ZVAL(subarray);
270 array_init(subarray);
271 for (p = s; p; p = p->next) {
272 if (p->data) {
273 add_next_index_string(subarray, p->data, 1);
274 }
275 }
276 add_assoc_zval_ex(&array, "ssl_engines", sizeof("ssl_engines"), subarray);
277 curl_slist_free_all(s);
278 }
279 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_COOKIELIST, &s)) {
280 MAKE_STD_ZVAL(subarray);
281 array_init(subarray);
282 for (p = s; p; p = p->next) {
283 if (p->data) {
284 add_next_index_string(subarray, p->data, 1);
285 }
286 }
287 add_assoc_zval_ex(&array, "cookies", sizeof("cookies"), subarray);
288 curl_slist_free_all(s);
289 }
290 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) {
291 add_assoc_string_ex(&array, "redirect_url", sizeof("redirect_url"), c ? c : "", 1);
292 }
293 #if PHP_HTTP_CURL_VERSION(7,19,0)
294 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) {
295 add_assoc_string_ex(&array, "primary_ip", sizeof("primary_ip"), c ? c : "", 1);
296 }
297 #endif
298 #if PHP_HTTP_CURL_VERSION(7,19,0)
299 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) {
300 add_assoc_double_ex(&array, "appconnect_time", sizeof("appconnect_time"), d);
301 }
302 #endif
303 #if PHP_HTTP_CURL_VERSION(7,19,4)
304 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) {
305 add_assoc_long_ex(&array, "condition_unmet", sizeof("condition_unmet"), l);
306 }
307 #endif
308 #if PHP_HTTP_CURL_VERSION(7,21,0)
309 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) {
310 add_assoc_long_ex(&array, "primary_port", sizeof("primary_port"), l);
311 }
312 #endif
313 #if PHP_HTTP_CURL_VERSION(7,21,0)
314 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) {
315 add_assoc_string_ex(&array, "local_ip", sizeof("local_ip"), c ? c : "", 1);
316 }
317 #endif
318 #if PHP_HTTP_CURL_VERSION(7,21,0)
319 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) {
320 add_assoc_long_ex(&array, "local_port", sizeof("local_port"), l);
321 }
322 #endif
323
324 /* END::CURLINFO */
325
326 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
327 {
328 int i;
329 zval *ci_array;
330 struct curl_certinfo *ci;
331 char *colon, *keyname;
332
333 if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) {
334 MAKE_STD_ZVAL(ci_array);
335 array_init(ci_array);
336
337 for (i = 0; i < ci->num_of_certs; ++i) {
338 s = ci->certinfo[i];
339
340 MAKE_STD_ZVAL(subarray);
341 array_init(subarray);
342 for (p = s; p; p = p->next) {
343 if (p->data) {
344 if ((colon = strchr(p->data, ':'))) {
345 keyname = estrndup(p->data, colon - p->data);
346 add_assoc_string_ex(subarray, keyname, colon - p->data + 1, colon + 1, 1);
347 efree(keyname);
348 } else {
349 add_next_index_string(subarray, p->data, 1);
350 }
351 }
352 }
353 add_next_index_zval(ci_array, subarray);
354 }
355 add_assoc_zval_ex(&array, "certinfo", sizeof("certinfo"), ci_array);
356 }
357 }
358 #endif
359 add_assoc_string_ex(&array, "error", sizeof("error"), php_http_curl_client_get_storage(ch)->errorbuffer, 1);
360
361 return SUCCESS;
362 }
363
364 /* curl client options */
365
366 static php_http_options_t php_http_curl_client_options;
367
368 #define PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN 0x0001
369 #define PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR 0x0002
370 #define PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS 0x0004
371
372 static STATUS php_http_curl_client_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata)
373 {
374 php_http_client_t *h = userdata;
375 php_http_curl_client_t *curl = h->ctx;
376 CURL *ch = curl->handle;
377
378 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_BVAL_P(val) ? 2 : 0)) {
379 return FAILURE;
380 }
381 return SUCCESS;
382 }
383
384 static STATUS php_http_curl_client_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata)
385 {
386 php_http_client_t *h = userdata;
387 php_http_curl_client_t *curl = h->ctx;
388 CURL *ch = curl->handle;
389
390 if (val) {
391 php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle);
392
393 if (storage->cookiestore) {
394 pefree(storage->cookiestore, 1);
395 }
396 storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1);
397 if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore)
398 || CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)
399 ) {
400 return FAILURE;
401 }
402 }
403 return SUCCESS;
404 }
405
406 static STATUS php_http_curl_client_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata)
407 {
408 php_http_client_t *h = userdata;
409 php_http_curl_client_t *curl = h->ctx;
410 CURL *ch = curl->handle;
411 TSRMLS_FETCH_FROM_CTX(h->ts);
412
413 if (val && Z_TYPE_P(val) != IS_NULL) {
414 if (curl->options.encode_cookies) {
415 if (SUCCESS == php_http_url_encode_hash_ex(HASH_OF(val), &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0 TSRMLS_CC)) {
416 php_http_buffer_fix(&curl->options.cookies);
417 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
418 return FAILURE;
419 }
420 } else {
421 return FAILURE;
422 }
423 } else {
424 HashPosition pos;
425 php_http_array_hashkey_t cookie_key = php_http_array_hashkey_init(0);
426 zval **cookie_val;
427
428 FOREACH_KEYVAL(pos, val, cookie_key, cookie_val) {
429 zval *zv = php_http_ztyp(IS_STRING, *cookie_val);
430
431 php_http_array_hashkey_stringify(&cookie_key);
432 php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.str, Z_STRVAL_P(zv));
433 php_http_array_hashkey_stringfree(&cookie_key);
434
435 zval_ptr_dtor(&zv);
436 }
437
438 php_http_buffer_fix(&curl->options.cookies);
439 if (curl->options.cookies.used) {
440 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
441 return FAILURE;
442 }
443 }
444 }
445 }
446 return SUCCESS;
447 }
448
449 static STATUS php_http_curl_client_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata)
450 {
451 php_http_client_t *h = userdata;
452 php_http_curl_client_t *curl = h->ctx;
453
454 curl->options.encode_cookies = Z_BVAL_P(val);
455 return SUCCESS;
456 }
457
458 static STATUS php_http_curl_client_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata)
459 {
460 php_http_client_t *h = userdata;
461 php_http_curl_client_t *curl = h->ctx;
462 CURL *ch = curl->handle;
463 TSRMLS_FETCH_FROM_CTX(h->ts);
464
465 if (Z_LVAL_P(val)) {
466 if (Z_LVAL_P(val) > 0) {
467 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) {
468 return FAILURE;
469 }
470 } else {
471 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) PHP_HTTP_G->env.request.time + Z_LVAL_P(val))) {
472 return FAILURE;
473 }
474 }
475 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) {
476 return FAILURE;
477 }
478 } else {
479 if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0)
480 || CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0)
481 ) {
482 return FAILURE;
483 }
484 }
485 return SUCCESS;
486 }
487
488 static STATUS php_http_curl_client_option_set_compress(php_http_option_t *opt, zval *val, void *userdata)
489 {
490 php_http_client_t *h = userdata;
491 php_http_curl_client_t *curl = h->ctx;
492
493 if (Z_BVAL_P(val)) {
494 curl->options.headers = curl_slist_append(curl->options.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
495 }
496 return SUCCESS;
497 }
498
499 static STATUS php_http_curl_client_option_set_etag(php_http_option_t *opt, zval *val, void *userdata)
500 {
501 php_http_client_t *h = userdata;
502 php_http_curl_client_t *curl = h->ctx;
503 php_http_buffer_t header;
504 zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"'));
505
506 php_http_buffer_init(&header);
507 php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val));
508 php_http_buffer_fix(&header);
509 curl->options.headers = curl_slist_append(curl->options.headers, header.data);
510 php_http_buffer_dtor(&header);
511 return SUCCESS;
512 }
513
514 static STATUS php_http_curl_client_option_set_range(php_http_option_t *opt, zval *val, void *userdata)
515 {
516 php_http_client_t *h = userdata;
517 php_http_curl_client_t *curl = h->ctx;
518 CURL *ch = curl->handle;
519 TSRMLS_FETCH_FROM_CTX(h->ts);
520
521 php_http_buffer_reset(&curl->options.ranges);
522
523 if (val && Z_TYPE_P(val) != IS_NULL) {
524 HashPosition pos;
525 zval **rr, **rb, **re;
526
527 FOREACH_VAL(pos, val, rr) {
528 if (Z_TYPE_PP(rr) == IS_ARRAY) {
529 if (2 == php_http_array_list(Z_ARRVAL_PP(rr) TSRMLS_CC, 2, &rb, &re)) {
530 if ( ((Z_TYPE_PP(rb) == IS_LONG) || ((Z_TYPE_PP(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(rb), Z_STRLEN_PP(rb), NULL, NULL, 1))) &&
531 ((Z_TYPE_PP(re) == IS_LONG) || ((Z_TYPE_PP(re) == IS_STRING) && is_numeric_string(Z_STRVAL_PP(re), Z_STRLEN_PP(re), NULL, NULL, 1)))) {
532 zval *rbl = php_http_ztyp(IS_LONG, *rb);
533 zval *rel = php_http_ztyp(IS_LONG, *re);
534
535 if ((Z_LVAL_P(rbl) >= 0) && (Z_LVAL_P(rel) >= 0)) {
536 php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", Z_LVAL_P(rbl), Z_LVAL_P(rel));
537 }
538 zval_ptr_dtor(&rbl);
539 zval_ptr_dtor(&rel);
540 }
541
542 }
543 }
544 }
545
546 if (curl->options.ranges.used) {
547 curl->options.range_request = 1;
548 /* ditch last comma */
549 curl->options.ranges.data[curl->options.ranges.used - 1] = '\0';
550 }
551 }
552
553 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) {
554 return FAILURE;
555 }
556 return SUCCESS;
557 }
558
559 static STATUS php_http_curl_client_option_set_resume(php_http_option_t *opt, zval *val, void *userdata)
560 {
561 php_http_client_t *h = userdata;
562 php_http_curl_client_t *curl = h->ctx;
563 CURL *ch = curl->handle;
564
565 if (Z_LVAL_P(val) > 0) {
566 curl->options.range_request = 1;
567 }
568 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) {
569 return FAILURE;
570 }
571 return SUCCESS;
572 }
573
574 static STATUS php_http_curl_client_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata)
575 {
576 php_http_client_t *h = userdata;
577 php_http_curl_client_t *curl = h->ctx;
578
579 curl->options.retry.delay = Z_DVAL_P(val);
580 return SUCCESS;
581 }
582
583 static STATUS php_http_curl_client_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata)
584 {
585 php_http_client_t *h = userdata;
586 php_http_curl_client_t *curl = h->ctx;
587
588 curl->options.retry.count = Z_LVAL_P(val);
589 return SUCCESS;
590 }
591
592 static STATUS php_http_curl_client_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata)
593 {
594 php_http_client_t *h = userdata;
595 php_http_curl_client_t *curl = h->ctx;
596 CURL *ch = curl->handle;
597
598 if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L)
599 || CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val))
600 ) {
601 return FAILURE;
602 }
603 return SUCCESS;
604 }
605
606 static STATUS php_http_curl_client_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata)
607 {
608 php_http_client_t *h = userdata;
609 php_http_curl_client_t *curl = h->ctx;
610 CURL *ch = curl->handle;
611 long localport = 0, localportrange = 0;
612 TSRMLS_FETCH_FROM_CTX(h->ts);
613
614 if (val && Z_TYPE_P(val) != IS_NULL) {
615 zval **z_port_start, *zps_copy = NULL, **z_port_end, *zpe_copy = NULL;
616
617 switch (php_http_array_list(Z_ARRVAL_P(val) TSRMLS_CC, 2, &z_port_start, &z_port_end)) {
618 case 2:
619 zps_copy = php_http_ztyp(IS_LONG, *z_port_start);
620 zpe_copy = php_http_ztyp(IS_LONG, *z_port_end);
621 localportrange = labs(Z_LVAL_P(zps_copy)-Z_LVAL_P(zpe_copy))+1L;
622 /* no break */
623 case 1:
624 if (!zps_copy) {
625 zps_copy = php_http_ztyp(IS_LONG, *z_port_start);
626 }
627 localport = (zpe_copy && Z_LVAL_P(zpe_copy) > 0) ? MIN(Z_LVAL_P(zps_copy), Z_LVAL_P(zpe_copy)) : Z_LVAL_P(zps_copy);
628 zval_ptr_dtor(&zps_copy);
629 if (zpe_copy) {
630 zval_ptr_dtor(&zpe_copy);
631 }
632 break;
633 default:
634 break;
635 }
636 }
637 if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport)
638 || CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange)
639 ) {
640 return FAILURE;
641 }
642 return SUCCESS;
643 }
644
645 #if PHP_HTTP_CURL_VERSION(7,21,3)
646 static STATUS php_http_curl_client_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata)
647 {
648 php_http_client_t *h = userdata;
649 php_http_curl_client_t *curl = h->ctx;
650 CURL *ch = curl->handle;
651 TSRMLS_FETCH_FROM_CTX(h->ts);
652
653 if (val && Z_TYPE_P(val) != IS_NULL) {
654 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
655 HashPosition pos;
656 zval **data;
657
658 FOREACH_KEYVAL(pos, val, key, data) {
659 zval *cpy = php_http_ztyp(IS_STRING, *data);
660 curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy));
661 zval_ptr_dtor(&cpy);
662 }
663
664 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) {
665 return FAILURE;
666 }
667 } else {
668 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) {
669 return FAILURE;
670 }
671 }
672 return SUCCESS;
673 }
674 #endif
675
676 static void php_http_curl_client_options_init(php_http_options_t *registry TSRMLS_DC)
677 {
678 php_http_option_t *opt;
679
680 /* proxy */
681 if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) {
682 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
683 }
684 php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG);
685 php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG);
686 if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) {
687 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
688 }
689 php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG);
690 php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL);
691 #if PHP_HTTP_CURL_VERSION(7,19,4)
692 php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING);
693 #endif
694
695 /* dns */
696 if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) {
697 Z_LVAL(opt->defval) = 60;
698 }
699 php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG);
700 #if PHP_HTTP_CURL_VERSION(7,21,3)
701 if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) {
702 opt->setter = php_http_curl_client_option_set_resolve;
703 }
704 #endif
705 #if PHP_HTTP_CURL_VERSION(7,24,0)
706 if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) {
707 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
708 }
709 #endif
710
711 /* limits */
712 php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG);
713 php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG);
714
715 /* LSF weirdance
716 php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG);
717 php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG);
718 */
719
720 /* connection handling */
721 /* crashes
722 if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) {
723 Z_LVAL(opt->defval) = 5;
724 }
725 */
726 php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL);
727 php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL);
728
729 /* outgoing interface */
730 php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING);
731 if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) {
732 opt->setter = php_http_curl_client_option_set_portrange;
733 }
734
735 /* another endpoint port */
736 php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG);
737
738 /* RFC4007 zone_id */
739 #if PHP_HTTP_CURL_VERSION(7,19,0)
740 php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG);
741 #endif
742
743 /* auth */
744 if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) {
745 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
746 }
747 php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG);
748
749 /* redirects */
750 if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
751 opt->setter = php_http_curl_client_option_set_redirect;
752 }
753 php_http_option_register(registry, ZEND_STRL("unrestrictedauth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL);
754 #if PHP_HTTP_CURL_VERSION(7,19,1)
755 php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_BOOL);
756 #else
757 php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POST301, IS_BOOL);
758 #endif
759
760 /* retries */
761 if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) {
762 opt->setter = php_http_curl_client_option_set_retrycount;
763 }
764 if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) {
765 opt->setter = php_http_curl_client_option_set_retrydelay;
766 }
767
768 /* referer */
769 if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) {
770 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
771 }
772 if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) {
773 ZVAL_BOOL(&opt->defval, 1);
774 }
775
776 /* useragent */
777 if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) {
778 /* don't check strlen, to allow sending no useragent at all */
779 ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0);
780 }
781
782 /* resume */
783 if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) {
784 opt->setter = php_http_curl_client_option_set_resume;
785 }
786 /* ranges */
787 if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) {
788 opt->setter = php_http_curl_client_option_set_range;
789 }
790
791 /* etag */
792 if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) {
793 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
794 opt->setter = php_http_curl_client_option_set_etag;
795 }
796
797 /* compression */
798 if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) {
799 opt->setter = php_http_curl_client_option_set_compress;
800 }
801
802 /* lastmodified */
803 if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) {
804 opt->setter = php_http_curl_client_option_set_lastmodified;
805 }
806
807 /* cookies */
808 if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) {
809 opt->setter = php_http_curl_client_option_set_encodecookies;
810 ZVAL_BOOL(&opt->defval, 1);
811 }
812 if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) {
813 opt->setter = php_http_curl_client_option_set_cookies;
814 }
815
816 /* cookiesession, don't load session cookies from cookiestore */
817 php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL);
818 /* cookiestore, read initial cookies from that file and store cookies back into that file */
819 if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) {
820 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
821 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
822 opt->setter = php_http_curl_client_option_set_cookiestore;
823 }
824
825 /* maxfilesize */
826 php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG);
827
828 /* http protocol version */
829 php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG);
830
831 /* timeouts */
832 if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) {
833 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS;
834 }
835 if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) {
836 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS;
837 Z_DVAL(opt->defval) = 3;
838 }
839
840 /* tcp */
841 #if PHP_HTTP_CURL_VERSION(7,25,0)
842 php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL);
843 if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) {
844 Z_LVAL(opt->defval) = 60;
845 }
846 if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) {
847 Z_LVAL(opt->defval) = 60;
848 }
849 #endif
850
851 /* ssl */
852 if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
853 registry = &opt->suboptions;
854
855 if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
856 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
857 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
858 }
859 php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING);
860 php_http_option_register(registry, ZEND_STRL("certpasswd"), CURLOPT_SSLCERTPASSWD, IS_STRING);
861
862 if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
863 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
864 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
865 }
866 php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING);
867 php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING);
868 php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
869 php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
870 if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
871 ZVAL_BOOL(&opt->defval, 1);
872 }
873 if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) {
874 ZVAL_BOOL(&opt->defval, 1);
875 opt->setter = php_http_curl_client_option_set_ssl_verifyhost;
876 }
877 php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
878 if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
879 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
880 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
881 #ifdef PHP_HTTP_CURL_CAINFO
882 ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0);
883 #endif
884 }
885 if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
886 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
887 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
888 }
889 if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
890 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
891 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
892 }
893 if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
894 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
895 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
896 }
897 #if PHP_HTTP_CURL_VERSION(7,19,0)
898 if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
899 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
900 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
901 }
902 # ifdef PHP_HTTP_HAVE_OPENSSL
903 if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
904 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
905 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
906 }
907 # endif
908 #endif
909 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
910 php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
911 #endif
912 }
913 }
914
915 static zval *php_http_curl_client_get_option(php_http_option_t *opt, HashTable *options, void *userdata)
916 {
917 php_http_client_t *h = userdata;
918 php_http_curl_client_t *curl = h->ctx;
919 zval *option;
920
921 if ((option = php_http_option_get(opt, options, NULL))) {
922 option = php_http_ztyp(opt->type, option);
923 zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL);
924 }
925 return option;
926 }
927
928 static STATUS php_http_curl_client_set_option(php_http_option_t *opt, zval *val, void *userdata)
929 {
930 php_http_client_t *h = userdata;
931 php_http_curl_client_t *curl = h->ctx;
932 CURL *ch = curl->handle;
933 zval tmp;
934 STATUS rv = SUCCESS;
935 TSRMLS_FETCH_FROM_CTX(h->ts);
936
937 if (!val) {
938 val = &opt->defval;
939 }
940
941 switch (opt->type) {
942 case IS_BOOL:
943 if (opt->setter) {
944 rv = opt->setter(opt, val, h);
945 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) {
946 rv = FAILURE;
947 }
948 break;
949
950 case IS_LONG:
951 if (opt->setter) {
952 rv = opt->setter(opt, val, h);
953 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) {
954 rv = FAILURE;
955 }
956 break;
957
958 case IS_STRING:
959 if (!(opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) {
960 if (!(opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR) || !Z_STRVAL_P(val) || SUCCESS == php_check_open_basedir(Z_STRVAL_P(val) TSRMLS_CC)) {
961 if (opt->setter) {
962 rv = opt->setter(opt, val, h);
963 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) {
964 rv = FAILURE;
965 }
966 }
967 }
968 break;
969
970 case IS_DOUBLE:
971 if (opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS) {
972 tmp = *val;
973 Z_DVAL(tmp) *= 1000;
974 val = &tmp;
975 }
976 if (opt->setter) {
977 rv = opt->setter(opt, val, h);
978 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) {
979 rv = FAILURE;
980 }
981 break;
982
983 case IS_ARRAY:
984 if (opt->setter) {
985 rv = opt->setter(opt, val, h);
986 } else if (Z_TYPE_P(val) != IS_NULL) {
987 rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), h);
988 }
989 break;
990
991 default:
992 if (opt->setter) {
993 rv = opt->setter(opt, val, h);
994 } else {
995 rv = FAILURE;
996 }
997 break;
998 }
999 if (rv != SUCCESS) {
1000 php_http_error(HE_NOTICE, PHP_HTTP_E_CLIENT, "Could not set option %s", opt->name.s);
1001 }
1002 return rv;
1003 }
1004
1005 /* client ops */
1006
1007 static STATUS php_http_curl_client_reset(php_http_client_t *h);
1008
1009 static php_http_client_t *php_http_curl_client_init(php_http_client_t *h, void *handle)
1010 {
1011 php_http_curl_client_t *ctx;
1012 TSRMLS_FETCH_FROM_CTX(h->ts);
1013
1014 if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL TSRMLS_CC))) {
1015 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "could not initialize curl handle");
1016 return NULL;
1017 }
1018
1019 ctx = ecalloc(1, sizeof(*ctx));
1020 ctx->handle = handle;
1021 php_http_buffer_init(&ctx->options.cookies);
1022 php_http_buffer_init(&ctx->options.ranges);
1023 zend_hash_init(&ctx->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0);
1024 h->ctx = ctx;
1025
1026 #if defined(ZTS)
1027 curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
1028 #endif
1029 curl_easy_setopt(handle, CURLOPT_HEADER, 0L);
1030 curl_easy_setopt(handle, CURLOPT_FILETIME, 1L);
1031 curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L);
1032 curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
1033 curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
1034 curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL);
1035 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curl_client_dummy_callback);
1036 curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curl_client_raw_callback);
1037 curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curl_client_read_callback);
1038 curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curl_client_ioctl_callback);
1039 curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curl_client_progress_callback);
1040 curl_easy_setopt(handle, CURLOPT_DEBUGDATA, h);
1041 curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, h);
1042
1043 php_http_curl_client_reset(h);
1044
1045 return h;
1046 }
1047
1048 static php_http_client_t *php_http_curl_client_copy(php_http_client_t *from, php_http_client_t *to)
1049 {
1050 php_http_curl_client_t *ctx = from->ctx;
1051 void *copy;
1052 TSRMLS_FETCH_FROM_CTX(from->ts);
1053
1054 if (!(copy = php_resource_factory_handle_copy(from->rf, ctx->handle TSRMLS_CC))) {
1055 return NULL;
1056 }
1057
1058 if (to) {
1059 return php_http_curl_client_init(to, copy);
1060 } else {
1061 return php_http_client_init(NULL, from->ops, from->rf, copy TSRMLS_CC);
1062 }
1063 }
1064
1065 static void php_http_curl_client_dtor(php_http_client_t *h)
1066 {
1067 php_http_curl_client_t *ctx = h->ctx;
1068 TSRMLS_FETCH_FROM_CTX(h->ts);
1069
1070 curl_easy_setopt(ctx->handle, CURLOPT_NOPROGRESS, 1L);
1071 curl_easy_setopt(ctx->handle, CURLOPT_PROGRESSFUNCTION, NULL);
1072 curl_easy_setopt(ctx->handle, CURLOPT_VERBOSE, 0L);
1073 curl_easy_setopt(ctx->handle, CURLOPT_DEBUGFUNCTION, NULL);
1074
1075 php_resource_factory_handle_dtor(h->rf, ctx->handle TSRMLS_CC);
1076
1077 php_http_buffer_dtor(&ctx->options.ranges);
1078 php_http_buffer_dtor(&ctx->options.cookies);
1079 zend_hash_destroy(&ctx->options.cache);
1080
1081 if (ctx->options.headers) {
1082 curl_slist_free_all(ctx->options.headers);
1083 ctx->options.headers = NULL;
1084 }
1085 php_http_client_progress_dtor(&ctx->progress TSRMLS_CC);
1086
1087 efree(ctx);
1088 h->ctx = NULL;
1089 }
1090
1091 static STATUS php_http_curl_client_reset(php_http_client_t *h)
1092 {
1093 php_http_curl_client_t *curl = h->ctx;
1094 CURL *ch = curl->handle;
1095 php_http_curl_client_storage_t *st;
1096
1097 if ((st = php_http_curl_client_get_storage(ch))) {
1098 if (st->url) {
1099 pefree(st->url, 1);
1100 st->url = NULL;
1101 }
1102 if (st->cookiestore) {
1103 pefree(st->cookiestore, 1);
1104 st->cookiestore = NULL;
1105 }
1106 st->errorbuffer[0] = '\0';
1107 }
1108
1109 curl_easy_setopt(ch, CURLOPT_URL, NULL);
1110 /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
1111 #if PHP_HTTP_CURL_VERSION(7,19,1)
1112 curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL);
1113 curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL);
1114 curl_easy_setopt(ch, CURLOPT_USERNAME, NULL);
1115 curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL);
1116 #endif
1117
1118 #if PHP_HTTP_CURL_VERSION(7,21,3)
1119 if (curl->options.resolve) {
1120 curl_slist_free_all(curl->options.resolve);
1121 curl->options.resolve = NULL;
1122 }
1123 #endif
1124 curl->options.retry.count = 0;
1125 curl->options.retry.delay = 0;
1126 curl->options.redirects = 0;
1127 curl->options.encode_cookies = 1;
1128
1129 if (curl->options.headers) {
1130 curl_slist_free_all(curl->options.headers);
1131 curl->options.headers = NULL;
1132 }
1133
1134 php_http_buffer_reset(&curl->options.cookies);
1135 php_http_buffer_reset(&curl->options.ranges);
1136
1137 return SUCCESS;
1138 }
1139
1140 PHP_HTTP_API STATUS php_http_curl_client_prepare(php_http_client_t *h, php_http_message_t *msg)
1141 {
1142 size_t body_size;
1143 php_http_curl_client_t *curl = h->ctx;
1144 php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle);
1145 TSRMLS_FETCH_FROM_CTX(h->ts);
1146
1147 /* request url */
1148 if (!PHP_HTTP_INFO(msg).request.url) {
1149 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot request empty URL");
1150 return FAILURE;
1151 }
1152 storage->errorbuffer[0] = '\0';
1153 if (storage->url) {
1154 pefree(storage->url, 1);
1155 }
1156 storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 1);
1157 curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url);
1158
1159 /* request method */
1160 switch (php_http_select_str(PHP_HTTP_INFO(msg).request.method, 4, "GET", "HEAD", "POST", "PUT")) {
1161 case 0:
1162 curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1L);
1163 break;
1164
1165 case 1:
1166 curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L);
1167 break;
1168
1169 case 2:
1170 curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
1171 break;
1172
1173 case 3:
1174 curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
1175 break;
1176
1177 default: {
1178 if (PHP_HTTP_INFO(msg).request.method) {
1179 curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
1180 } else {
1181 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD, "Cannot use empty request method");
1182 return FAILURE;
1183 }
1184 break;
1185 }
1186 }
1187
1188 /* request headers */
1189 php_http_message_update_headers(msg);
1190 if (zend_hash_num_elements(&msg->hdrs)) {
1191 php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0);
1192 zval **header_val;
1193 HashPosition pos;
1194 php_http_buffer_t header;
1195
1196 php_http_buffer_init(&header);
1197 FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) {
1198 if (header_key.type == HASH_KEY_IS_STRING) {
1199 zval *header_cpy = php_http_ztyp(IS_STRING, *header_val);
1200
1201 php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy));
1202 php_http_buffer_fix(&header);
1203 curl->options.headers = curl_slist_append(curl->options.headers, header.data);
1204 php_http_buffer_reset(&header);
1205
1206 zval_ptr_dtor(&header_cpy);
1207 }
1208 }
1209 php_http_buffer_dtor(&header);
1210 curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
1211 }
1212
1213 /* attach request body */
1214 if ((body_size = php_http_message_body_size(msg->body))) {
1215 /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the
1216 * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.«
1217 * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the
1218 * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method
1219 * does not allow a request body.
1220 */
1221 php_stream_rewind(php_http_message_body_stream(msg->body));
1222 curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, msg->body);
1223 curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body);
1224 curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
1225 curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
1226 }
1227
1228 return SUCCESS;
1229 }
1230
1231 static STATUS php_http_curl_client_exec(php_http_client_t *h, php_http_message_t *msg)
1232 {
1233 uint tries = 0;
1234 CURLcode result;
1235 php_http_curl_client_t *curl = h->ctx;
1236 php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle);
1237 TSRMLS_FETCH_FROM_CTX(h->ts);
1238
1239 if (SUCCESS != php_http_curl_client_prepare(h, msg)) {
1240 return FAILURE;
1241 }
1242
1243 retry:
1244 if (CURLE_OK != (result = curl_easy_perform(curl->handle))) {
1245 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "%s; %s (%s)", curl_easy_strerror(result), storage->errorbuffer, storage->url);
1246
1247 if (EG(exception)) {
1248 add_property_long(EG(exception), "curlCode", result);
1249 }
1250
1251 if (curl->options.retry.count > tries++) {
1252 switch (result) {
1253 case CURLE_COULDNT_RESOLVE_PROXY:
1254 case CURLE_COULDNT_RESOLVE_HOST:
1255 case CURLE_COULDNT_CONNECT:
1256 case CURLE_WRITE_ERROR:
1257 case CURLE_READ_ERROR:
1258 case CURLE_OPERATION_TIMEDOUT:
1259 case CURLE_SSL_CONNECT_ERROR:
1260 case CURLE_GOT_NOTHING:
1261 case CURLE_SSL_ENGINE_SETFAILED:
1262 case CURLE_SEND_ERROR:
1263 case CURLE_RECV_ERROR:
1264 case CURLE_SSL_ENGINE_INITFAILED:
1265 case CURLE_LOGIN_DENIED:
1266 if (curl->options.retry.delay >= PHP_HTTP_DIFFSEC) {
1267 php_http_sleep(curl->options.retry.delay);
1268 }
1269 goto retry;
1270 default:
1271 break;
1272 }
1273 } else {
1274 return FAILURE;
1275 }
1276 }
1277
1278 return SUCCESS;
1279 }
1280
1281 static STATUS php_http_curl_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
1282 {
1283 php_http_curl_client_t *curl = h->ctx;
1284 TSRMLS_FETCH_FROM_CTX(h->ts);
1285
1286 switch (opt) {
1287 case PHP_HTTP_CLIENT_OPT_SETTINGS:
1288 return php_http_options_apply(&php_http_curl_client_options, arg, h);
1289 break;
1290
1291 case PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK:
1292 if (curl->progress.in_cb) {
1293 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot change progress callback while executing it");
1294 return FAILURE;
1295 }
1296 if (curl->progress.callback) {
1297 php_http_client_progress_dtor(&curl->progress TSRMLS_CC);
1298 }
1299 curl->progress.callback = arg;
1300 break;
1301
1302 case PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE:
1303 /* are cookies already enabled anyway? */
1304 if (!php_http_curl_client_get_storage(curl->handle)->cookiestore) {
1305 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIEFILE, "")) {
1306 return FAILURE;
1307 }
1308 }
1309 break;
1310
1311 case PHP_HTTP_CLIENT_OPT_COOKIES_RESET:
1312 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "ALL")) {
1313 return FAILURE;
1314 }
1315 break;
1316
1317 case PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION:
1318 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "SESS")) {
1319 return FAILURE;
1320 }
1321 break;
1322
1323 case PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH:
1324 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "FLUSH")) {
1325 return FAILURE;
1326 }
1327 break;
1328
1329 default:
1330 return FAILURE;
1331 }
1332
1333 return SUCCESS;
1334 }
1335
1336 static STATUS php_http_curl_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg)
1337 {
1338 php_http_curl_client_t *curl = h->ctx;
1339
1340 switch (opt) {
1341 case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO:
1342 *((php_http_client_progress_t **) arg) = &curl->progress;
1343 break;
1344
1345 case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO:
1346 get_info(curl->handle, arg);
1347 break;
1348
1349 default:
1350 return FAILURE;
1351 }
1352
1353 return SUCCESS;
1354 }
1355
1356 static php_resource_factory_ops_t php_http_curl_client_resource_factory_ops = {
1357 php_http_curl_ctor,
1358 php_http_curl_copy,
1359 php_http_curl_dtor
1360 };
1361
1362 static php_http_client_ops_t php_http_curl_client_ops = {
1363 &php_http_curl_client_resource_factory_ops,
1364 php_http_curl_client_init,
1365 php_http_curl_client_copy,
1366 php_http_curl_client_dtor,
1367 php_http_curl_client_reset,
1368 php_http_curl_client_exec,
1369 php_http_curl_client_setopt,
1370 php_http_curl_client_getopt,
1371 (php_http_new_t) php_http_curl_client_object_new_ex,
1372 php_http_curl_client_get_class_entry
1373 };
1374
1375 PHP_HTTP_API php_http_client_ops_t *php_http_curl_client_get_ops(void)
1376 {
1377 return &php_http_curl_client_ops;
1378 }
1379
1380
1381 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientCURL, method, 0, req_args)
1382 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientCURL, method, 0)
1383 #define PHP_HTTP_CURL_CLIENT_ME(method, visibility) PHP_ME(HttpClientCURL, method, PHP_HTTP_ARGS(HttpClientCURL, method), visibility)
1384 #define PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(me, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##me), PHP_HTTP_ARGS(HttpClientCURL, me), vis)
1385
1386 PHP_HTTP_BEGIN_ARGS(send, 0)
1387 PHP_HTTP_ARG_VAL(request, 0)
1388 PHP_HTTP_END_ARGS;
1389
1390 static zend_class_entry *php_http_curl_client_class_entry;
1391
1392 zend_class_entry *php_http_curl_client_get_class_entry(void)
1393 {
1394 return php_http_curl_client_class_entry;
1395 }
1396
1397 static zend_function_entry php_http_curl_client_method_entry[] = {
1398 PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(send, ZEND_ACC_PUBLIC)
1399 EMPTY_FUNCTION_ENTRY
1400 };
1401
1402 zend_object_value php_http_curl_client_object_new(zend_class_entry *ce TSRMLS_DC)
1403 {
1404 return php_http_curl_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
1405 }
1406
1407 zend_object_value php_http_curl_client_object_new_ex(zend_class_entry *ce, php_http_client_t *r, php_http_client_object_t **ptr TSRMLS_DC)
1408 {
1409 zend_object_value ov;
1410 php_http_client_object_t *o;
1411
1412 o = ecalloc(1, sizeof(php_http_client_object_t));
1413 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
1414 object_properties_init((zend_object *) o, ce);
1415
1416 if (!(o->client = r)) {
1417 o->client = php_http_client_init(NULL, &php_http_curl_client_ops, NULL, NULL TSRMLS_CC);
1418 }
1419
1420 if (ptr) {
1421 *ptr = o;
1422 }
1423
1424 ov.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC);
1425 ov.handlers = php_http_client_get_object_handlers();
1426
1427 return ov;
1428 }
1429
1430
1431 PHP_MINIT_FUNCTION(http_curl_client)
1432 {
1433 php_http_options_t *options;
1434
1435 if (SUCCESS != php_persistent_handle_provide(ZEND_STRL("http_client.curl"), &php_http_curl_client_resource_factory_ops, NULL, NULL)) {
1436 return FAILURE;
1437 }
1438
1439 if ((options = php_http_options_init(&php_http_curl_client_options, 1))) {
1440 options->getter = php_http_curl_client_get_option;
1441 options->setter = php_http_curl_client_set_option;
1442
1443 php_http_curl_client_options_init(options TSRMLS_CC);
1444 }
1445
1446 PHP_HTTP_REGISTER_CLASS(http\\Curl, Client, http_curl_client, php_http_client_get_class_entry(), 0);
1447 php_http_curl_client_class_entry->create_object = php_http_curl_client_object_new;
1448
1449 /*
1450 * HTTP Protocol Version Constants
1451 */
1452 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_0"), CURL_HTTP_VERSION_1_0 TSRMLS_CC);
1453 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_1"), CURL_HTTP_VERSION_1_1 TSRMLS_CC);
1454 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_NONE"), CURL_HTTP_VERSION_NONE TSRMLS_CC); /* to be removed */
1455 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_ANY"), CURL_HTTP_VERSION_NONE TSRMLS_CC);
1456
1457 /*
1458 * SSL Version Constants
1459 */
1460 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_TLSv1"), CURL_SSLVERSION_TLSv1 TSRMLS_CC);
1461 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv2"), CURL_SSLVERSION_SSLv2 TSRMLS_CC);
1462 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv3"), CURL_SSLVERSION_SSLv3 TSRMLS_CC);
1463 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_ANY"), CURL_SSLVERSION_DEFAULT TSRMLS_CC);
1464
1465 /*
1466 * DNS IPvX resolving
1467 */
1468 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V4"), CURL_IPRESOLVE_V4 TSRMLS_CC);
1469 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V6"), CURL_IPRESOLVE_V6 TSRMLS_CC);
1470 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_ANY"), CURL_IPRESOLVE_WHATEVER TSRMLS_CC);
1471
1472 /*
1473 * Auth Constants
1474 */
1475 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_BASIC"), CURLAUTH_BASIC TSRMLS_CC);
1476 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST"), CURLAUTH_DIGEST TSRMLS_CC);
1477 #if PHP_HTTP_CURL_VERSION(7,19,3)
1478 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST_IE"), CURLAUTH_DIGEST_IE TSRMLS_CC);
1479 #endif
1480 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_NTLM"), CURLAUTH_NTLM TSRMLS_CC);
1481 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_GSSNEG"), CURLAUTH_GSSNEGOTIATE TSRMLS_CC);
1482 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_ANY"), CURLAUTH_ANY TSRMLS_CC);
1483
1484 /*
1485 * Proxy Type Constants
1486 */
1487 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4"), CURLPROXY_SOCKS4 TSRMLS_CC);
1488 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4A"), CURLPROXY_SOCKS5 TSRMLS_CC);
1489 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5_HOSTNAME"), CURLPROXY_SOCKS5 TSRMLS_CC);
1490 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5"), CURLPROXY_SOCKS5 TSRMLS_CC);
1491 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP"), CURLPROXY_HTTP TSRMLS_CC);
1492 # if PHP_HTTP_CURL_VERSION(7,19,4)
1493 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP_1_0"), CURLPROXY_HTTP_1_0 TSRMLS_CC);
1494 # endif
1495
1496 /*
1497 * Post Redirection Constants
1498 */
1499 #if PHP_HTTP_CURL_VERSION(7,19,1)
1500 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_301"), CURL_REDIR_POST_301 TSRMLS_CC);
1501 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_302"), CURL_REDIR_POST_302 TSRMLS_CC);
1502 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_ALL"), CURL_REDIR_POST_ALL TSRMLS_CC);
1503 #endif
1504
1505 return SUCCESS;
1506 }
1507
1508 PHP_MSHUTDOWN_FUNCTION(http_curl_client)
1509 {
1510 php_http_options_dtor(&php_http_curl_client_options);
1511 return SUCCESS;
1512 }
1513
1514 /*
1515 * Local variables:
1516 * tab-width: 4
1517 * c-basic-offset: 4
1518 * End:
1519 * vim600: noet sw=4 ts=4 fdm=marker
1520 * vim<600: noet sw=4 ts=4
1521 */