640f3bbf5cdf5365aebb45d913eabcfc1116dbe3
[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 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 (PHP_HTTP_BUFFER_LEN(&curl->options.cookies)) {
440 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, PHP_HTTP_BUFFER_VAL(&curl->options.cookies))) {
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, PHP_HTTP_BUFFER_VAL(&header));
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 (PHP_HTTP_BUFFER_LEN(&curl->options.ranges)) {
547 curl->options.range_request = 1;
548 /* ditch last comma */
549 PHP_HTTP_BUFFER_VAL(&curl->options.ranges)[PHP_HTTP_BUFFER_LEN(&curl->options.ranges)-- -1] = '\0';
550 }
551 }
552
553 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, PHP_HTTP_BUFFER_VAL(&curl->options.ranges))) {
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 static STATUS php_http_curl_client_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata)
646 {
647 php_http_client_t *h = userdata;
648 php_http_curl_client_t *curl = h->ctx;
649 CURL *ch = curl->handle;
650 TSRMLS_FETCH_FROM_CTX(h->ts);
651
652 if (val && Z_TYPE_P(val) != IS_NULL) {
653 php_http_array_hashkey_t key = php_http_array_hashkey_init(0);
654 HashPosition pos;
655 zval **data;
656
657 FOREACH_KEYVAL(pos, val, key, data) {
658 zval *cpy = php_http_ztyp(IS_STRING, *data);
659 curl->options.resolve = curl_slist_append(curl->options.resolve, Z_STRVAL_P(cpy));
660 zval_ptr_dtor(&cpy);
661 }
662
663 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) {
664 return FAILURE;
665 }
666 } else {
667 if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) {
668 return FAILURE;
669 }
670 }
671 return SUCCESS;
672 }
673
674 static void php_http_curl_client_options_init(php_http_options_t *registry TSRMLS_DC)
675 {
676 php_http_option_t *opt;
677
678 /* proxy */
679 if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) {
680 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
681 }
682 php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG);
683 php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG);
684 if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) {
685 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
686 }
687 php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG);
688 php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, IS_BOOL);
689 #if PHP_HTTP_CURL_VERSION(7,19,4)
690 php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING);
691 #endif
692
693 /* dns */
694 if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) {
695 Z_LVAL(opt->defval) = 60;
696 }
697 php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG);
698 #if PHP_HTTP_CURL_VERSION(7,21,3)
699 if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) {
700 opt->setter = php_http_curl_client_option_set_resolve;
701 }
702 #endif
703 #if PHP_HTTP_CURL_VERSION(7,24,0)
704 if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) {
705 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
706 }
707 #endif
708
709 /* limits */
710 php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG);
711 php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG);
712
713 /* LSF weirdance
714 php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG);
715 php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG);
716 */
717
718 /* connection handling */
719 /* crashes
720 if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) {
721 Z_LVAL(opt->defval) = 5;
722 }
723 */
724 php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, IS_BOOL);
725 php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, IS_BOOL);
726
727 /* outgoing interface */
728 php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING);
729 if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) {
730 opt->setter = php_http_curl_client_option_set_portrange;
731 }
732
733 /* another endpoint port */
734 php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG);
735
736 /* RFC4007 zone_id */
737 #if PHP_HTTP_CURL_VERSION(7,19,0)
738 php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG);
739 #endif
740
741 /* auth */
742 if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) {
743 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
744 }
745 php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG);
746
747 /* redirects */
748 if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
749 opt->setter = php_http_curl_client_option_set_redirect;
750 }
751 php_http_option_register(registry, ZEND_STRL("unrestrictedauth"), CURLOPT_UNRESTRICTED_AUTH, IS_BOOL);
752 #if PHP_HTTP_CURL_VERSION(7,19,1)
753 php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_BOOL);
754 #else
755 php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POST301, IS_BOOL);
756 #endif
757
758 /* retries */
759 if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) {
760 opt->setter = php_http_curl_client_option_set_retrycount;
761 }
762 if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) {
763 opt->setter = php_http_curl_client_option_set_retrydelay;
764 }
765
766 /* referer */
767 if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) {
768 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
769 }
770 if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, IS_BOOL))) {
771 ZVAL_BOOL(&opt->defval, 1);
772 }
773
774 /* useragent */
775 if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) {
776 /* don't check strlen, to allow sending no useragent at all */
777 ZVAL_STRING(&opt->defval, "PECL::HTTP/" PHP_HTTP_EXT_VERSION " (PHP/" PHP_VERSION ")", 0);
778 }
779
780 /* resume */
781 if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) {
782 opt->setter = php_http_curl_client_option_set_resume;
783 }
784 /* ranges */
785 if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) {
786 opt->setter = php_http_curl_client_option_set_range;
787 }
788
789 /* etag */
790 if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) {
791 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
792 opt->setter = php_http_curl_client_option_set_etag;
793 }
794
795 /* compression */
796 if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, IS_BOOL))) {
797 opt->setter = php_http_curl_client_option_set_compress;
798 }
799
800 /* lastmodified */
801 if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) {
802 opt->setter = php_http_curl_client_option_set_lastmodified;
803 }
804
805 /* cookies */
806 if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, IS_BOOL))) {
807 opt->setter = php_http_curl_client_option_set_encodecookies;
808 ZVAL_BOOL(&opt->defval, 1);
809 }
810 if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) {
811 opt->setter = php_http_curl_client_option_set_cookies;
812 }
813
814 /* cookiesession, don't load session cookies from cookiestore */
815 php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, IS_BOOL);
816 /* cookiestore, read initial cookies from that file and store cookies back into that file */
817 if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) {
818 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
819 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
820 opt->setter = php_http_curl_client_option_set_cookiestore;
821 }
822
823 /* maxfilesize */
824 php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG);
825
826 /* http protocol version */
827 php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG);
828
829 /* timeouts */
830 if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) {
831 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS;
832 }
833 if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) {
834 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS;
835 Z_DVAL(opt->defval) = 3;
836 }
837
838 /* tcp */
839 #if PHP_HTTP_CURL_VERSION(7,25,0)
840 php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, IS_BOOL);
841 if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) {
842 Z_LVAL(opt->defval) = 60;
843 }
844 if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) {
845 Z_LVAL(opt->defval) = 60;
846 }
847 #endif
848
849 /* ssl */
850 if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
851 registry = &opt->suboptions;
852
853 if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
854 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
855 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
856 }
857 php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING);
858 php_http_option_register(registry, ZEND_STRL("certpasswd"), CURLOPT_SSLCERTPASSWD, IS_STRING);
859
860 if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
861 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
862 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
863 }
864 php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING);
865 php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING);
866 php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
867 php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
868 if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, IS_BOOL))) {
869 ZVAL_BOOL(&opt->defval, 1);
870 }
871 if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, IS_BOOL))) {
872 ZVAL_BOOL(&opt->defval, 1);
873 opt->setter = php_http_curl_client_option_set_ssl_verifyhost;
874 }
875 php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
876 if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
877 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
878 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
879 #ifdef PHP_HTTP_CURL_CAINFO
880 ZVAL_STRING(&opt->defval, PHP_HTTP_CURL_CAINFO, 0);
881 #endif
882 }
883 if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
884 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
885 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
886 }
887 if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
888 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
889 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
890 }
891 if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
892 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
893 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
894 }
895 #if PHP_HTTP_CURL_VERSION(7,19,0)
896 if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
897 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
898 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
899 }
900 # ifdef PHP_HTTP_HAVE_OPENSSL
901 if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
902 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN;
903 opt->flags |= PHP_HTTP_CURL_CLIENT_OPTION_CHECK_BASEDIR;
904 }
905 # endif
906 #endif
907 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
908 php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, IS_BOOL);
909 #endif
910 }
911 }
912
913 static zval *php_http_curl_client_get_option(php_http_option_t *opt, HashTable *options, void *userdata)
914 {
915 php_http_client_t *h = userdata;
916 php_http_curl_client_t *curl = h->ctx;
917 zval *option;
918
919 if ((option = php_http_option_get(opt, options, NULL))) {
920 option = php_http_ztyp(opt->type, option);
921 zend_hash_quick_update(&curl->options.cache, opt->name.s, opt->name.l, opt->name.h, &option, sizeof(zval *), NULL);
922 }
923 return option;
924 }
925
926 static STATUS php_http_curl_client_set_option(php_http_option_t *opt, zval *val, void *userdata)
927 {
928 php_http_client_t *h = userdata;
929 php_http_curl_client_t *curl = h->ctx;
930 CURL *ch = curl->handle;
931 zval tmp;
932 STATUS rv = SUCCESS;
933 TSRMLS_FETCH_FROM_CTX(h->ts);
934
935 if (!val) {
936 val = &opt->defval;
937 }
938
939 switch (opt->type) {
940 case IS_BOOL:
941 if (opt->setter) {
942 rv = opt->setter(opt, val, h);
943 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_BVAL_P(val))) {
944 rv = FAILURE;
945 }
946 break;
947
948 case IS_LONG:
949 if (opt->setter) {
950 rv = opt->setter(opt, val, h);
951 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) {
952 rv = FAILURE;
953 }
954 break;
955
956 case IS_STRING:
957 if (!(opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_CHECK_STRLEN) || Z_STRLEN_P(val)) {
958 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)) {
959 if (opt->setter) {
960 rv = opt->setter(opt, val, h);
961 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val))) {
962 rv = FAILURE;
963 }
964 }
965 }
966 break;
967
968 case IS_DOUBLE:
969 if (opt->flags & PHP_HTTP_CURL_CLIENT_OPTION_TRANSFORM_MS) {
970 tmp = *val;
971 Z_DVAL(tmp) *= 1000;
972 val = &tmp;
973 }
974 if (opt->setter) {
975 rv = opt->setter(opt, val, h);
976 } else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) {
977 rv = FAILURE;
978 }
979 break;
980
981 case IS_ARRAY:
982 if (opt->setter) {
983 rv = opt->setter(opt, val, h);
984 } else if (Z_TYPE_P(val) != IS_NULL) {
985 rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), h);
986 }
987 break;
988
989 default:
990 if (opt->setter) {
991 rv = opt->setter(opt, val, h);
992 } else {
993 rv = FAILURE;
994 }
995 break;
996 }
997 if (rv != SUCCESS) {
998 php_http_error(HE_NOTICE, PHP_HTTP_E_CLIENT, "Could not set option %s", opt->name.s);
999 }
1000 return rv;
1001 }
1002
1003 /* client ops */
1004
1005 static STATUS php_http_curl_client_reset(php_http_client_t *h);
1006
1007 static php_http_client_t *php_http_curl_client_init(php_http_client_t *h, void *handle)
1008 {
1009 php_http_curl_client_t *ctx;
1010 TSRMLS_FETCH_FROM_CTX(h->ts);
1011
1012 if (!handle && !(handle = php_http_resource_factory_handle_ctor(h->rf TSRMLS_CC))) {
1013 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "could not initialize curl handle");
1014 return NULL;
1015 }
1016
1017 ctx = ecalloc(1, sizeof(*ctx));
1018 ctx->handle = handle;
1019 php_http_buffer_init(&ctx->options.cookies);
1020 php_http_buffer_init(&ctx->options.ranges);
1021 zend_hash_init(&ctx->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0);
1022 h->ctx = ctx;
1023
1024 #if defined(ZTS)
1025 curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
1026 #endif
1027 curl_easy_setopt(handle, CURLOPT_HEADER, 0L);
1028 curl_easy_setopt(handle, CURLOPT_FILETIME, 1L);
1029 curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L);
1030 curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
1031 curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
1032 curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, NULL);
1033 curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curl_client_dummy_callback);
1034 curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curl_client_raw_callback);
1035 curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curl_client_read_callback);
1036 curl_easy_setopt(handle, CURLOPT_IOCTLFUNCTION, php_http_curl_client_ioctl_callback);
1037 curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curl_client_progress_callback);
1038 curl_easy_setopt(handle, CURLOPT_DEBUGDATA, h);
1039 curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, h);
1040
1041 php_http_curl_client_reset(h);
1042
1043 return h;
1044 }
1045
1046 static php_http_client_t *php_http_curl_client_copy(php_http_client_t *from, php_http_client_t *to)
1047 {
1048 php_http_curl_client_t *ctx = from->ctx;
1049 void *copy;
1050 TSRMLS_FETCH_FROM_CTX(from->ts);
1051
1052 if (!(copy = php_http_resource_factory_handle_copy(from->rf, ctx->handle TSRMLS_CC))) {
1053 return NULL;
1054 }
1055
1056 if (to) {
1057 return php_http_curl_client_init(to, copy);
1058 } else {
1059 return php_http_client_init(NULL, from->ops, from->rf, copy TSRMLS_CC);
1060 }
1061 }
1062
1063 static void php_http_curl_client_dtor(php_http_client_t *h)
1064 {
1065 php_http_curl_client_t *ctx = h->ctx;
1066 TSRMLS_FETCH_FROM_CTX(h->ts);
1067
1068 curl_easy_setopt(ctx->handle, CURLOPT_NOPROGRESS, 1L);
1069 curl_easy_setopt(ctx->handle, CURLOPT_PROGRESSFUNCTION, NULL);
1070 curl_easy_setopt(ctx->handle, CURLOPT_VERBOSE, 0L);
1071 curl_easy_setopt(ctx->handle, CURLOPT_DEBUGFUNCTION, NULL);
1072
1073 php_http_resource_factory_handle_dtor(h->rf, ctx->handle TSRMLS_CC);
1074
1075 php_http_buffer_dtor(&ctx->options.ranges);
1076 php_http_buffer_dtor(&ctx->options.cookies);
1077 zend_hash_destroy(&ctx->options.cache);
1078
1079 if (ctx->options.headers) {
1080 curl_slist_free_all(ctx->options.headers);
1081 ctx->options.headers = NULL;
1082 }
1083 php_http_client_progress_dtor(&ctx->progress TSRMLS_CC);
1084
1085 efree(ctx);
1086 h->ctx = NULL;
1087 }
1088
1089 static STATUS php_http_curl_client_reset(php_http_client_t *h)
1090 {
1091 php_http_curl_client_t *curl = h->ctx;
1092 CURL *ch = curl->handle;
1093 php_http_curl_client_storage_t *st;
1094
1095 if ((st = php_http_curl_client_get_storage(ch))) {
1096 if (st->url) {
1097 pefree(st->url, 1);
1098 st->url = NULL;
1099 }
1100 if (st->cookiestore) {
1101 pefree(st->cookiestore, 1);
1102 st->cookiestore = NULL;
1103 }
1104 st->errorbuffer[0] = '\0';
1105 }
1106
1107 curl_easy_setopt(ch, CURLOPT_URL, NULL);
1108 /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
1109 #if PHP_HTTP_CURL_VERSION(7,19,1)
1110 curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL);
1111 curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL);
1112 curl_easy_setopt(ch, CURLOPT_USERNAME, NULL);
1113 curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL);
1114 #endif
1115
1116 #if PHP_HTTP_CURL_VERSION(7,21,3)
1117 if (curl->options.resolve) {
1118 curl_slist_free_all(curl->options.resolve);
1119 curl->options.resolve = NULL;
1120 }
1121 #endif
1122 curl->options.retry.count = 0;
1123 curl->options.retry.delay = 0;
1124 curl->options.redirects = 0;
1125 curl->options.encode_cookies = 1;
1126
1127 if (curl->options.headers) {
1128 curl_slist_free_all(curl->options.headers);
1129 curl->options.headers = NULL;
1130 }
1131
1132 php_http_buffer_reset(&curl->options.cookies);
1133 php_http_buffer_reset(&curl->options.ranges);
1134
1135 return SUCCESS;
1136 }
1137
1138 PHP_HTTP_API STATUS php_http_curl_client_prepare(php_http_client_t *h, php_http_message_t *msg)
1139 {
1140 size_t body_size;
1141 php_http_curl_client_t *curl = h->ctx;
1142 php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle);
1143 TSRMLS_FETCH_FROM_CTX(h->ts);
1144
1145 /* request url */
1146 if (!PHP_HTTP_INFO(msg).request.url) {
1147 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot request empty URL");
1148 return FAILURE;
1149 }
1150 storage->errorbuffer[0] = '\0';
1151 if (storage->url) {
1152 pefree(storage->url, 1);
1153 }
1154 storage->url = pestrdup(PHP_HTTP_INFO(msg).request.url, 1);
1155 curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url);
1156
1157 /* request method */
1158 switch (php_http_select_str(PHP_HTTP_INFO(msg).request.method, 4, "GET", "HEAD", "POST", "PUT")) {
1159 case 0:
1160 curl_easy_setopt(curl->handle, CURLOPT_HTTPGET, 1L);
1161 break;
1162
1163 case 1:
1164 curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L);
1165 break;
1166
1167 case 2:
1168 curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
1169 break;
1170
1171 case 3:
1172 curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
1173 break;
1174
1175 default: {
1176 if (PHP_HTTP_INFO(msg).request.method) {
1177 curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
1178 } else {
1179 php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_METHOD, "Cannot use empty request method");
1180 return FAILURE;
1181 }
1182 break;
1183 }
1184 }
1185
1186 /* request headers */
1187 php_http_message_update_headers(msg);
1188 if (zend_hash_num_elements(&msg->hdrs)) {
1189 php_http_array_hashkey_t header_key = php_http_array_hashkey_init(0);
1190 zval **header_val;
1191 HashPosition pos;
1192 php_http_buffer_t header;
1193
1194 php_http_buffer_init(&header);
1195 FOREACH_HASH_KEYVAL(pos, &msg->hdrs, header_key, header_val) {
1196 if (header_key.type == HASH_KEY_IS_STRING) {
1197 zval *header_cpy = php_http_ztyp(IS_STRING, *header_val);
1198
1199 php_http_buffer_appendf(&header, "%s: %s", header_key.str, Z_STRVAL_P(header_cpy));
1200 php_http_buffer_fix(&header);
1201 curl->options.headers = curl_slist_append(curl->options.headers, PHP_HTTP_BUFFER_VAL(&header));
1202 php_http_buffer_reset(&header);
1203
1204 zval_ptr_dtor(&header_cpy);
1205 }
1206 }
1207 php_http_buffer_dtor(&header);
1208 curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
1209 }
1210
1211 /* attach request body */
1212 if ((body_size = php_http_message_body_size(&msg->body))) {
1213 /* RFC2616, section 4.3 (para. 4) states that »a message-body MUST NOT be included in a request if the
1214 * specification of the request method (section 5.1.1) does not allow sending an entity-body in request.«
1215 * Following the clause in section 5.1.1 (para. 2) that request methods »MUST be implemented with the
1216 * same semantics as those specified in section 9« reveal that not any single defined HTTP/1.1 method
1217 * does not allow a request body.
1218 */
1219 php_stream_rewind(php_http_message_body_stream(&msg->body));
1220 curl_easy_setopt(curl->handle, CURLOPT_IOCTLDATA, &msg->body);
1221 curl_easy_setopt(curl->handle, CURLOPT_READDATA, &msg->body);
1222 curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
1223 curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
1224 }
1225
1226 return SUCCESS;
1227 }
1228
1229 static STATUS php_http_curl_client_exec(php_http_client_t *h, php_http_message_t *msg)
1230 {
1231 uint tries = 0;
1232 CURLcode result;
1233 php_http_curl_client_t *curl = h->ctx;
1234 php_http_curl_client_storage_t *storage = php_http_curl_client_get_storage(curl->handle);
1235 TSRMLS_FETCH_FROM_CTX(h->ts);
1236
1237 if (SUCCESS != php_http_curl_client_prepare(h, msg)) {
1238 return FAILURE;
1239 }
1240
1241 retry:
1242 if (CURLE_OK != (result = curl_easy_perform(curl->handle))) {
1243 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "%s; %s (%s)", curl_easy_strerror(result), storage->errorbuffer, storage->url);
1244
1245 if (EG(exception)) {
1246 add_property_long(EG(exception), "curlCode", result);
1247 }
1248
1249 if (curl->options.retry.count > tries++) {
1250 switch (result) {
1251 case CURLE_COULDNT_RESOLVE_PROXY:
1252 case CURLE_COULDNT_RESOLVE_HOST:
1253 case CURLE_COULDNT_CONNECT:
1254 case CURLE_WRITE_ERROR:
1255 case CURLE_READ_ERROR:
1256 case CURLE_OPERATION_TIMEDOUT:
1257 case CURLE_SSL_CONNECT_ERROR:
1258 case CURLE_GOT_NOTHING:
1259 case CURLE_SSL_ENGINE_SETFAILED:
1260 case CURLE_SEND_ERROR:
1261 case CURLE_RECV_ERROR:
1262 case CURLE_SSL_ENGINE_INITFAILED:
1263 case CURLE_LOGIN_DENIED:
1264 if (curl->options.retry.delay >= PHP_HTTP_DIFFSEC) {
1265 php_http_sleep(curl->options.retry.delay);
1266 }
1267 goto retry;
1268 default:
1269 break;
1270 }
1271 } else {
1272 return FAILURE;
1273 }
1274 }
1275
1276 return SUCCESS;
1277 }
1278
1279 static STATUS php_http_curl_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
1280 {
1281 php_http_curl_client_t *curl = h->ctx;
1282 TSRMLS_FETCH_FROM_CTX(h->ts);
1283
1284 switch (opt) {
1285 case PHP_HTTP_CLIENT_OPT_SETTINGS:
1286 return php_http_options_apply(&php_http_curl_client_options, arg, h);
1287 break;
1288
1289 case PHP_HTTP_CLIENT_OPT_PROGRESS_CALLBACK:
1290 if (curl->progress.in_cb) {
1291 php_http_error(HE_WARNING, PHP_HTTP_E_CLIENT, "Cannot change progress callback while executing it");
1292 return FAILURE;
1293 }
1294 if (curl->progress.callback) {
1295 php_http_client_progress_dtor(&curl->progress TSRMLS_CC);
1296 }
1297 curl->progress.callback = arg;
1298 break;
1299
1300 case PHP_HTTP_CLIENT_OPT_COOKIES_ENABLE:
1301 /* are cookies already enabled anyway? */
1302 if (!php_http_curl_client_get_storage(curl->handle)->cookiestore) {
1303 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIEFILE, "")) {
1304 return FAILURE;
1305 }
1306 }
1307 break;
1308
1309 case PHP_HTTP_CLIENT_OPT_COOKIES_RESET:
1310 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "ALL")) {
1311 return FAILURE;
1312 }
1313 break;
1314
1315 case PHP_HTTP_CLIENT_OPT_COOKIES_RESET_SESSION:
1316 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "SESS")) {
1317 return FAILURE;
1318 }
1319 break;
1320
1321 case PHP_HTTP_CLIENT_OPT_COOKIES_FLUSH:
1322 if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_COOKIELIST, "FLUSH")) {
1323 return FAILURE;
1324 }
1325 break;
1326
1327 default:
1328 return FAILURE;
1329 }
1330
1331 return SUCCESS;
1332 }
1333
1334 static STATUS php_http_curl_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg)
1335 {
1336 php_http_curl_client_t *curl = h->ctx;
1337
1338 switch (opt) {
1339 case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO:
1340 *((php_http_client_progress_t **) arg) = &curl->progress;
1341 break;
1342
1343 case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO:
1344 get_info(curl->handle, arg);
1345 break;
1346
1347 default:
1348 return FAILURE;
1349 }
1350
1351 return SUCCESS;
1352 }
1353
1354 static php_http_resource_factory_ops_t php_http_curl_client_resource_factory_ops = {
1355 php_http_curl_ctor,
1356 php_http_curl_copy,
1357 php_http_curl_dtor
1358 };
1359
1360 static php_http_client_ops_t php_http_curl_client_ops = {
1361 &php_http_curl_client_resource_factory_ops,
1362 php_http_curl_client_init,
1363 php_http_curl_client_copy,
1364 php_http_curl_client_dtor,
1365 php_http_curl_client_reset,
1366 php_http_curl_client_exec,
1367 php_http_curl_client_setopt,
1368 php_http_curl_client_getopt,
1369 (php_http_new_t) php_http_curl_client_object_new_ex,
1370 php_http_curl_client_get_class_entry
1371 };
1372
1373 PHP_HTTP_API php_http_client_ops_t *php_http_curl_client_get_ops(void)
1374 {
1375 return &php_http_curl_client_ops;
1376 }
1377
1378
1379 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpClientCURL, method, 0, req_args)
1380 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpClientCURL, method, 0)
1381 #define PHP_HTTP_CURL_CLIENT_ME(method, visibility) PHP_ME(HttpClientCURL, method, PHP_HTTP_ARGS(HttpClientCURL, method), visibility)
1382 #define PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(me, vis) ZEND_FENTRY(me, ZEND_MN(HttpClient_##me), PHP_HTTP_ARGS(HttpClientCURL, me), vis)
1383
1384 PHP_HTTP_BEGIN_ARGS(send, 0)
1385 PHP_HTTP_ARG_VAL(request, 0)
1386 PHP_HTTP_END_ARGS;
1387
1388 static zend_class_entry *php_http_curl_client_class_entry;
1389
1390 zend_class_entry *php_http_curl_client_get_class_entry(void)
1391 {
1392 return php_http_curl_client_class_entry;
1393 }
1394
1395 static zend_function_entry php_http_curl_client_method_entry[] = {
1396 PHP_HTTP_CURL_CLIENT_CLIENT_MALIAS(send, ZEND_ACC_PUBLIC)
1397 EMPTY_FUNCTION_ENTRY
1398 };
1399
1400 zend_object_value php_http_curl_client_object_new(zend_class_entry *ce TSRMLS_DC)
1401 {
1402 return php_http_curl_client_object_new_ex(ce, NULL, NULL TSRMLS_CC);
1403 }
1404
1405 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)
1406 {
1407 zend_object_value ov;
1408 php_http_client_object_t *o;
1409
1410 o = ecalloc(1, sizeof(php_http_client_object_t));
1411 zend_object_std_init((zend_object *) o, ce TSRMLS_CC);
1412 object_properties_init((zend_object *) o, ce);
1413
1414 if (!(o->client = r)) {
1415 o->client = php_http_client_init(NULL, &php_http_curl_client_ops, NULL, NULL TSRMLS_CC);
1416 }
1417
1418 if (ptr) {
1419 *ptr = o;
1420 }
1421
1422 ov.handle = zend_objects_store_put(o, NULL, php_http_client_object_free, NULL TSRMLS_CC);
1423 ov.handlers = php_http_client_get_object_handlers();
1424
1425 return ov;
1426 }
1427
1428
1429 PHP_MINIT_FUNCTION(http_curl_client)
1430 {
1431 php_http_options_t *options;
1432
1433 if (SUCCESS != php_http_persistent_handle_provide(ZEND_STRL("http_client.curl"), &php_http_curl_client_resource_factory_ops, NULL, NULL)) {
1434 return FAILURE;
1435 }
1436
1437 if ((options = php_http_options_init(&php_http_curl_client_options, 1))) {
1438 options->getter = php_http_curl_client_get_option;
1439 options->setter = php_http_curl_client_set_option;
1440
1441 php_http_curl_client_options_init(options TSRMLS_CC);
1442 }
1443
1444 PHP_HTTP_REGISTER_CLASS(http\\Curl, Client, http_curl_client, php_http_client_get_class_entry(), 0);
1445 php_http_curl_client_class_entry->create_object = php_http_curl_client_object_new;
1446
1447 /*
1448 * HTTP Protocol Version Constants
1449 */
1450 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_0"), CURL_HTTP_VERSION_1_0 TSRMLS_CC);
1451 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_1_1"), CURL_HTTP_VERSION_1_1 TSRMLS_CC);
1452 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 */
1453 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("HTTP_VERSION_ANY"), CURL_HTTP_VERSION_NONE TSRMLS_CC);
1454
1455 /*
1456 * SSL Version Constants
1457 */
1458 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_TLSv1"), CURL_SSLVERSION_TLSv1 TSRMLS_CC);
1459 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv2"), CURL_SSLVERSION_SSLv2 TSRMLS_CC);
1460 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_SSLv3"), CURL_SSLVERSION_SSLv3 TSRMLS_CC);
1461 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("SSL_VERSION_ANY"), CURL_SSLVERSION_DEFAULT TSRMLS_CC);
1462
1463 /*
1464 * DNS IPvX resolving
1465 */
1466 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V4"), CURL_IPRESOLVE_V4 TSRMLS_CC);
1467 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_V6"), CURL_IPRESOLVE_V6 TSRMLS_CC);
1468 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("IPRESOLVE_ANY"), CURL_IPRESOLVE_WHATEVER TSRMLS_CC);
1469
1470 /*
1471 * Auth Constants
1472 */
1473 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_BASIC"), CURLAUTH_BASIC TSRMLS_CC);
1474 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST"), CURLAUTH_DIGEST TSRMLS_CC);
1475 #if PHP_HTTP_CURL_VERSION(7,19,3)
1476 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_DIGEST_IE"), CURLAUTH_DIGEST_IE TSRMLS_CC);
1477 #endif
1478 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_NTLM"), CURLAUTH_NTLM TSRMLS_CC);
1479 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_GSSNEG"), CURLAUTH_GSSNEGOTIATE TSRMLS_CC);
1480 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("AUTH_ANY"), CURLAUTH_ANY TSRMLS_CC);
1481
1482 /*
1483 * Proxy Type Constants
1484 */
1485 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4"), CURLPROXY_SOCKS4 TSRMLS_CC);
1486 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS4A"), CURLPROXY_SOCKS5 TSRMLS_CC);
1487 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5_HOSTNAME"), CURLPROXY_SOCKS5 TSRMLS_CC);
1488 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_SOCKS5"), CURLPROXY_SOCKS5 TSRMLS_CC);
1489 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP"), CURLPROXY_HTTP TSRMLS_CC);
1490 # if PHP_HTTP_CURL_VERSION(7,19,4)
1491 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("PROXY_HTTP_1_0"), CURLPROXY_HTTP_1_0 TSRMLS_CC);
1492 # endif
1493
1494 /*
1495 * Post Redirection Constants
1496 */
1497 #if PHP_HTTP_CURL_VERSION(7,19,1)
1498 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_301"), CURL_REDIR_POST_301 TSRMLS_CC);
1499 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_302"), CURL_REDIR_POST_302 TSRMLS_CC);
1500 zend_declare_class_constant_long(php_http_curl_client_class_entry, ZEND_STRL("POSTREDIR_ALL"), CURL_REDIR_POST_ALL TSRMLS_CC);
1501 #endif
1502
1503 return SUCCESS;
1504 }
1505
1506 PHP_MSHUTDOWN_FUNCTION(http_curl_client)
1507 {
1508 php_http_options_dtor(&php_http_curl_client_options);
1509 return SUCCESS;
1510 }
1511
1512 /*
1513 * Local variables:
1514 * tab-width: 4
1515 * c-basic-offset: 4
1516 * End:
1517 * vim600: noet sw=4 ts=4 fdm=marker
1518 * vim<600: noet sw=4 ts=4
1519 */