2 +--------------------------------------------------------------------+
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-2010, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
13 /* $Id: php_http_request_api.c 298591 2010-04-26 11:46:55Z mike $ */
17 #ifdef PHP_HTTP_NEED_OPENSSL_TSL
18 static MUTEX_T
*php_http_openssl_tsl
= NULL
;
20 static void php_http_openssl_thread_lock(int mode
, int n
, const char * file
, int line
)
22 if (mode
& CRYPTO_LOCK
) {
23 tsrm_mutex_lock(php_http_openssl_tsl
[n
]);
25 tsrm_mutex_unlock(php_http_openssl_tsl
[n
]);
29 static ulong
php_http_openssl_thread_id(void)
31 return (ulong
) tsrm_thread_id();
34 #ifdef PHP_HTTP_NEED_GNUTLS_TSL
35 static int php_http_gnutls_mutex_create(void **m
)
37 if (*((MUTEX_T
*) m
) = tsrm_mutex_alloc()) {
44 static int php_http_gnutls_mutex_destroy(void **m
)
46 tsrm_mutex_free(*((MUTEX_T
*) m
));
50 static int php_http_gnutls_mutex_lock(void **m
)
52 return tsrm_mutex_lock(*((MUTEX_T
*) m
));
55 static int php_http_gnutls_mutex_unlock(void **m
)
57 return tsrm_mutex_unlock(*((MUTEX_T
*) m
));
60 static struct gcry_thread_cbs php_http_gnutls_tsl
= {
61 GCRY_THREAD_OPTION_USER
,
63 php_http_gnutls_mutex_create
,
64 php_http_gnutls_mutex_destroy
,
65 php_http_gnutls_mutex_lock
,
66 php_http_gnutls_mutex_unlock
71 /* safe curl wrappers */
72 #define init_curl_storage(ch) \
74 php_http_request_storage_t *st = pecalloc(1, sizeof(php_http_request_storage_t), 1); \
75 curl_easy_setopt(ch, CURLOPT_PRIVATE, st); \
76 curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer); \
79 static void *safe_curl_init(void)
83 if ((ch
= curl_easy_init())) {
84 init_curl_storage(ch
);
89 static void *safe_curl_copy(void *p
)
93 if ((ch
= curl_easy_duphandle(p
))) {
94 init_curl_storage(ch
);
99 static void safe_curl_dtor(void *p
) {
100 php_http_request_storage_t
*st
= php_http_request_storage_get(p
);
102 curl_easy_cleanup(p
);
108 if (st
->cookiestore
) {
109 pefree(st
->cookiestore
, 1);
115 static inline zval
*php_http_request_option(php_http_request_t
*request
, HashTable
*options
, char *key
, size_t keylen
, int type
);
116 static inline zval
*php_http_request_option_cache(php_http_request_t
*r
, char *key
, size_t keylen
, ulong h
, zval
*opt
);
117 static inline int php_http_request_cookies_enabled(php_http_request_t
*r
);
119 static size_t php_http_curl_read_callback(void *, size_t, size_t, void *);
120 static int php_http_curl_progress_callback(void *, double, double, double, double);
121 static int php_http_curl_raw_callback(CURL
*, curl_infotype
, char *, size_t, void *);
122 static int php_http_curl_dummy_callback(char *data
, size_t n
, size_t l
, void *s
) { return n
*l
; }
123 static curlioerr
php_http_curl_ioctl_callback(CURL
*, curliocmd
, void *);
125 PHP_HTTP_API CURL
* php_http_curl_init(CURL
*ch
, php_http_request_t
*request TSRMLS_DC
)
127 if (ch
|| (SUCCESS
== php_http_persistent_handle_acquire(ZEND_STRL("http_request"), &ch TSRMLS_CC
))) {
129 curl_easy_setopt(ch
, CURLOPT_NOSIGNAL
, 1L);
131 curl_easy_setopt(ch
, CURLOPT_HEADER
, 0L);
132 curl_easy_setopt(ch
, CURLOPT_FILETIME
, 1L);
133 curl_easy_setopt(ch
, CURLOPT_AUTOREFERER
, 1L);
134 curl_easy_setopt(ch
, CURLOPT_VERBOSE
, 1L);
135 curl_easy_setopt(ch
, CURLOPT_HEADERFUNCTION
, NULL
);
136 curl_easy_setopt(ch
, CURLOPT_DEBUGFUNCTION
, php_http_curl_raw_callback
);
137 curl_easy_setopt(ch
, CURLOPT_READFUNCTION
, php_http_curl_read_callback
);
138 curl_easy_setopt(ch
, CURLOPT_IOCTLFUNCTION
, php_http_curl_ioctl_callback
);
139 curl_easy_setopt(ch
, CURLOPT_WRITEFUNCTION
, php_http_curl_dummy_callback
);
143 curl_easy_setopt(ch
, CURLOPT_DEBUGDATA
, request
);
145 /* attach curl handle */
147 /* set defaults (also in php_http_request_reset()) */
148 php_http_request_defaults(request
);
154 PHP_HTTP_API CURL
*php_http_curl_copy(CURL
*ch TSRMLS_DC
)
158 if (SUCCESS
== php_http_persistent_handle_accrete(ZEND_STRL("http_request"), ch
, © TSRMLS_CC
)) {
163 PHP_HTTP_API
void php_http_curl_free(CURL
**ch TSRMLS_DC
)
166 curl_easy_setopt(*ch
, CURLOPT_NOPROGRESS
, 1L);
167 curl_easy_setopt(*ch
, CURLOPT_PROGRESSFUNCTION
, NULL
);
168 curl_easy_setopt(*ch
, CURLOPT_VERBOSE
, 0L);
169 curl_easy_setopt(*ch
, CURLOPT_DEBUGFUNCTION
, NULL
);
171 php_http_persistent_handle_release(ZEND_STRL("http_request"), ch TSRMLS_CC
);
175 PHP_HTTP_API php_http_request_t
*php_http_request_init(php_http_request_t
*request
, CURL
*ch
, php_http_request_method_t meth
, const char *url TSRMLS_DC
)
177 php_http_request_t
*r
;
182 r
= emalloc(sizeof(php_http_request_t
));
184 memset(r
, 0, sizeof(php_http_request_t
));
187 r
->url
= (url
) ? php_http_url_absolute(url
, 0) : NULL
;
188 r
->meth
= (meth
> 0) ? meth
: PHP_HTTP_GET
;
190 r
->parser
.ctx
= php_http_message_parser_init(NULL TSRMLS_CC
);
191 r
->parser
.msg
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
192 r
->parser
.buf
= php_http_buffer_init(NULL
);
194 php_http_buffer_init(&r
->_cache
.cookies
);
195 zend_hash_init(&r
->_cache
.options
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
197 TSRMLS_SET_CTX(r
->ts
);
202 PHP_HTTP_API
void php_http_request_dtor(php_http_request_t
*request
)
204 TSRMLS_FETCH_FROM_CTX(request
->ts
);
206 php_http_request_reset(request
);
207 php_http_curl_free(&request
->ch
);
208 php_http_message_body_free(&request
->body
);
209 php_http_message_parser_free(&request
->parser
.ctx
);
210 php_http_message_free(&request
->parser
.msg
);
211 php_http_buffer_free(&request
->parser
.buf
);
213 php_http_buffer_dtor(&request
->_cache
.cookies
);
214 zend_hash_destroy(&request
->_cache
.options
);
215 if (request
->_cache
.headers
) {
216 curl_slist_free_all(request
->_cache
.headers
);
217 request
->_cache
.headers
= NULL
;
219 if (request
->_progress
.callback
) {
220 zval_ptr_dtor(&request
->_progress
.callback
);
221 request
->_progress
.callback
= NULL
;
225 PHP_HTTP_API
void php_http_request_free(php_http_request_t
**request
)
228 TSRMLS_FETCH_FROM_CTX((*request
)->ts
);
229 php_http_request_dtor(*request
);
235 PHP_HTTP_API
void php_http_request_reset(php_http_request_t
*request
)
237 TSRMLS_FETCH_FROM_CTX(request
->ts
);
238 STR_SET(request
->url
, NULL
);
239 php_http_message_body_dtor(request
->body
);
240 php_http_request_defaults(request
);
243 php_http_request_storage_t
*st
= php_http_request_storage_get(request
->ch
);
250 if (st
->cookiestore
) {
251 pefree(st
->cookiestore
, 1);
252 st
->cookiestore
= NULL
;
254 st
->errorbuffer
[0] = '\0';
259 PHP_HTTP_API STATUS
php_http_request_enable_cookies(php_http_request_t
*request
)
262 TSRMLS_FETCH_FROM_CTX(request
->ts
);
264 PHP_HTTP_CHECK_CURL_INIT(request
->ch
, php_http_curl_init(request
->ch
, request TSRMLS_CC
), initialized
= 0);
265 if (initialized
&& (php_http_request_cookies_enabled(request
) || (CURLE_OK
== curl_easy_setopt(request
->ch
, CURLOPT_COOKIEFILE
, "")))) {
268 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Could not enable cookies for this session");
272 PHP_HTTP_API STATUS
php_http_request_reset_cookies(php_http_request_t
*request
, int session_only
)
275 TSRMLS_FETCH_FROM_CTX(request
->ts
);
277 PHP_HTTP_CHECK_CURL_INIT(request
->ch
, php_http_curl_init(request
->ch
, request TSRMLS_CC
), initialized
= 0);
279 if (!php_http_request_cookies_enabled(request
)) {
280 if (SUCCESS
!= php_http_request_enable_cookies(request
)) {
285 if (CURLE_OK
== curl_easy_setopt(request
->ch
, CURLOPT_COOKIELIST
, "SESS")) {
289 if (CURLE_OK
== curl_easy_setopt(request
->ch
, CURLOPT_COOKIELIST
, "ALL")) {
297 PHP_HTTP_API STATUS
php_http_request_flush_cookies(php_http_request_t
*request
)
300 TSRMLS_FETCH_FROM_CTX(request
->ts
);
302 PHP_HTTP_CHECK_CURL_INIT(request
->ch
, php_http_curl_init(request
->ch
, request TSRMLS_CC
), initialized
= 0);
304 if (!php_http_request_cookies_enabled(request
)) {
307 if (CURLE_OK
== curl_easy_setopt(request
->ch
, CURLOPT_COOKIELIST
, "FLUSH")) {
314 PHP_HTTP_API
void php_http_request_defaults(php_http_request_t
*request
)
317 PHP_HTTP_CURL_OPT(CURLOPT_NOPROGRESS
, 0L);
318 PHP_HTTP_CURL_OPT(CURLOPT_PROGRESSDATA
, request
);
319 PHP_HTTP_CURL_OPT(CURLOPT_PROGRESSFUNCTION
, php_http_curl_progress_callback
);
320 PHP_HTTP_CURL_OPT(CURLOPT_URL
, NULL
);
321 #if PHP_HTTP_CURL_VERSION(7,19,4)
322 PHP_HTTP_CURL_OPT(CURLOPT_NOPROXY
, NULL
);
324 PHP_HTTP_CURL_OPT(CURLOPT_PROXY
, NULL
);
325 PHP_HTTP_CURL_OPT(CURLOPT_PROXYPORT
, 0L);
326 PHP_HTTP_CURL_OPT(CURLOPT_PROXYTYPE
, 0L);
327 /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
328 #if PHP_HTTP_CURL_VERSION(7,19,1)
329 PHP_HTTP_CURL_OPT(CURLOPT_PROXYUSERNAME
, NULL
);
330 PHP_HTTP_CURL_OPT(CURLOPT_PROXYPASSWORD
, NULL
);
332 PHP_HTTP_CURL_OPT(CURLOPT_PROXYAUTH
, 0L);
333 PHP_HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL
, 0L);
334 PHP_HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT
, 60L);
335 PHP_HTTP_CURL_OPT(CURLOPT_IPRESOLVE
, 0);
336 PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT
, 0L);
337 PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME
, 0L);
339 PHP_HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) 0);
340 PHP_HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) 0);
343 PHP_HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, 5L); */
344 PHP_HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT
, 0L);
345 PHP_HTTP_CURL_OPT(CURLOPT_FORBID_REUSE
, 0L);
346 PHP_HTTP_CURL_OPT(CURLOPT_INTERFACE
, NULL
);
347 PHP_HTTP_CURL_OPT(CURLOPT_PORT
, 0L);
348 #if PHP_HTTP_CURL_VERSION(7,19,0)
349 PHP_HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE
, 0L);
351 PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORT
, 0L);
352 PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE
, 0L);
353 /* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
354 #if PHP_HTTP_CURL_VERSION(7,19,1)
355 PHP_HTTP_CURL_OPT(CURLOPT_USERNAME
, NULL
);
356 PHP_HTTP_CURL_OPT(CURLOPT_PASSWORD
, NULL
);
358 PHP_HTTP_CURL_OPT(CURLOPT_HTTPAUTH
, 0L);
359 PHP_HTTP_CURL_OPT(CURLOPT_ENCODING
, NULL
);
360 /* we do this ourself anyway */
361 PHP_HTTP_CURL_OPT(CURLOPT_HTTP_CONTENT_DECODING
, 0L);
362 PHP_HTTP_CURL_OPT(CURLOPT_HTTP_TRANSFER_DECODING
, 0L);
363 PHP_HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION
, 0L);
364 #if PHP_HTTP_CURL_VERSION(7,19,1)
365 PHP_HTTP_CURL_OPT(CURLOPT_POSTREDIR
, 0L);
367 PHP_HTTP_CURL_OPT(CURLOPT_POST301
, 0L);
369 PHP_HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH
, 0L);
370 PHP_HTTP_CURL_OPT(CURLOPT_REFERER
, NULL
);
371 PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT
, "PECL::HTTP/" PHP_HTTP_EXT_VERSION
" (PHP/" PHP_VERSION
")");
372 PHP_HTTP_CURL_OPT(CURLOPT_HTTPHEADER
, NULL
);
373 PHP_HTTP_CURL_OPT(CURLOPT_COOKIE
, NULL
);
374 PHP_HTTP_CURL_OPT(CURLOPT_COOKIESESSION
, 0L);
375 /* these options would enable curl's cookie engine by default which we don't want
376 PHP_HTTP_CURL_OPT(CURLOPT_COOKIEFILE, NULL);
377 PHP_HTTP_CURL_OPT(CURLOPT_COOKIEJAR, NULL); */
378 PHP_HTTP_CURL_OPT(CURLOPT_COOKIELIST
, NULL
);
379 PHP_HTTP_CURL_OPT(CURLOPT_RANGE
, NULL
);
380 PHP_HTTP_CURL_OPT(CURLOPT_RESUME_FROM
, 0L);
381 PHP_HTTP_CURL_OPT(CURLOPT_MAXFILESIZE
, 0L);
382 PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION
, 0L);
383 PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE
, 0L);
384 PHP_HTTP_CURL_OPT(CURLOPT_TIMEOUT
, 0L);
385 PHP_HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT
, 3);
386 PHP_HTTP_CURL_OPT(CURLOPT_SSLCERT
, NULL
);
387 PHP_HTTP_CURL_OPT(CURLOPT_SSLCERTTYPE
, NULL
);
388 PHP_HTTP_CURL_OPT(CURLOPT_SSLCERTPASSWD
, NULL
);
389 PHP_HTTP_CURL_OPT(CURLOPT_SSLKEY
, NULL
);
390 PHP_HTTP_CURL_OPT(CURLOPT_SSLKEYTYPE
, NULL
);
391 PHP_HTTP_CURL_OPT(CURLOPT_SSLKEYPASSWD
, NULL
);
392 PHP_HTTP_CURL_OPT(CURLOPT_SSLENGINE
, NULL
);
393 PHP_HTTP_CURL_OPT(CURLOPT_SSLVERSION
, 0L);
394 PHP_HTTP_CURL_OPT(CURLOPT_SSL_VERIFYPEER
, 0L);
395 PHP_HTTP_CURL_OPT(CURLOPT_SSL_VERIFYHOST
, 0L);
396 PHP_HTTP_CURL_OPT(CURLOPT_SSL_CIPHER_LIST
, NULL
);
397 #if PHP_HTTP_CURL_VERSION(7,19,0)
398 PHP_HTTP_CURL_OPT(CURLOPT_ISSUERCERT
, NULL
);
399 #if defined(PHP_HTTP_HAVE_OPENSSL)
400 PHP_HTTP_CURL_OPT(CURLOPT_CRLFILE
, NULL
);
403 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
404 PHP_HTTP_CURL_OPT(CURLOPT_CERTINFO
, NULL
);
406 #ifdef PHP_HTTP_CURL_CAINFO
407 PHP_HTTP_CURL_OPT(CURLOPT_CAINFO
, PHP_HTTP_CURL_CAINFO
);
409 PHP_HTTP_CURL_OPT(CURLOPT_CAINFO
, NULL
);
411 PHP_HTTP_CURL_OPT(CURLOPT_CAPATH
, NULL
);
412 PHP_HTTP_CURL_OPT(CURLOPT_RANDOM_FILE
, NULL
);
413 PHP_HTTP_CURL_OPT(CURLOPT_EGDSOCKET
, NULL
);
414 PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDS
, NULL
);
415 PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE
, 0L);
416 PHP_HTTP_CURL_OPT(CURLOPT_HTTPPOST
, NULL
);
417 PHP_HTTP_CURL_OPT(CURLOPT_IOCTLDATA
, NULL
);
418 PHP_HTTP_CURL_OPT(CURLOPT_READDATA
, NULL
);
419 PHP_HTTP_CURL_OPT(CURLOPT_INFILESIZE
, 0L);
420 PHP_HTTP_CURL_OPT(CURLOPT_HTTP_VERSION
, CURL_HTTP_VERSION_NONE
);
421 PHP_HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST
, NULL
);
422 PHP_HTTP_CURL_OPT(CURLOPT_NOBODY
, 0L);
423 PHP_HTTP_CURL_OPT(CURLOPT_POST
, 0L);
424 PHP_HTTP_CURL_OPT(CURLOPT_UPLOAD
, 0L);
425 PHP_HTTP_CURL_OPT(CURLOPT_HTTPGET
, 1L);
429 PHP_HTTP_API
void php_http_request_set_progress_callback(php_http_request_t
*request
, zval
*cb
)
431 if (request
->_progress
.callback
) {
432 zval_ptr_dtor(&request
->_progress
.callback
);
434 if ((request
->_progress
.callback
= cb
)) {
439 PHP_HTTP_API STATUS
php_http_request_prepare(php_http_request_t
*request
, HashTable
*options
)
442 zend_bool range_req
= 0;
443 php_http_request_storage_t
*storage
;
445 TSRMLS_FETCH_FROM_CTX(request
->ts
);
447 PHP_HTTP_CHECK_CURL_INIT(request
->ch
, php_http_curl_init(NULL
, request TSRMLS_CC
), return FAILURE
);
449 if (!(storage
= php_http_request_storage_get(request
->ch
))) {
452 storage
->errorbuffer
[0] = '\0';
455 pefree(storage
->url
, 1);
457 storage
->url
= pestrdup(request
->url
, 1);
458 PHP_HTTP_CURL_OPT(CURLOPT_URL
, storage
->url
);
460 /* progress callback */
461 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("onprogress"), -1))) {
462 php_http_request_set_progress_callback(request
, zoption
);
466 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxyhost"), IS_STRING
))) {
467 PHP_HTTP_CURL_OPT(CURLOPT_PROXY
, Z_STRVAL_P(zoption
));
469 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxytype"), IS_LONG
))) {
470 PHP_HTTP_CURL_OPT(CURLOPT_PROXYTYPE
, Z_LVAL_P(zoption
));
473 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxyport"), IS_LONG
))) {
474 PHP_HTTP_CURL_OPT(CURLOPT_PROXYPORT
, Z_LVAL_P(zoption
));
477 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxyauth"), IS_STRING
)) && Z_STRLEN_P(zoption
)) {
478 PHP_HTTP_CURL_OPT(CURLOPT_PROXYUSERPWD
, Z_STRVAL_P(zoption
));
481 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxyauthtype"), IS_LONG
))) {
482 PHP_HTTP_CURL_OPT(CURLOPT_PROXYAUTH
, Z_LVAL_P(zoption
));
485 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("proxytunnel"), IS_BOOL
)) && Z_BVAL_P(zoption
)) {
486 PHP_HTTP_CURL_OPT(CURLOPT_HTTPPROXYTUNNEL
, 1L);
489 #if PHP_HTTP_CURL_VERSION(7,19,4)
490 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("noproxy"), IS_STRING
))) {
491 PHP_HTTP_CURL_OPT(CURLOPT_NOPROXY
, Z_STRVAL_P(zoption
));
496 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("dns_cache_timeout"), IS_LONG
))) {
497 PHP_HTTP_CURL_OPT(CURLOPT_DNS_CACHE_TIMEOUT
, Z_LVAL_P(zoption
));
499 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("ipresolve"), IS_LONG
)) && Z_LVAL_P(zoption
)) {
500 PHP_HTTP_CURL_OPT(CURLOPT_IPRESOLVE
, Z_LVAL_P(zoption
));
504 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("low_speed_limit"), IS_LONG
))) {
505 PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_LIMIT
, Z_LVAL_P(zoption
));
507 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("low_speed_time"), IS_LONG
))) {
508 PHP_HTTP_CURL_OPT(CURLOPT_LOW_SPEED_TIME
, Z_LVAL_P(zoption
));
511 if ((zoption = php_http_request_option(request, options, ZEND_STRS("max_send_speed"), IS_LONG))) {
512 PHP_HTTP_CURL_OPT(CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
514 if ((zoption = php_http_request_option(request, options, ZEND_STRS("max_recv_speed"), IS_LONG))) {
515 PHP_HTTP_CURL_OPT(CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t) Z_LVAL_P(zoption));
519 if ((zoption = php_http_request_option(request, options, ZEND_STRS("maxconnects"), IS_LONG))) {
520 PHP_HTTP_CURL_OPT(CURLOPT_MAXCONNECTS, Z_LVAL_P(zoption));
522 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("fresh_connect"), IS_BOOL
)) && Z_BVAL_P(zoption
)) {
523 PHP_HTTP_CURL_OPT(CURLOPT_FRESH_CONNECT
, 1L);
525 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("forbid_reuse"), IS_BOOL
)) && Z_BVAL_P(zoption
)) {
526 PHP_HTTP_CURL_OPT(CURLOPT_FORBID_REUSE
, 1L);
529 /* outgoing interface */
530 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("interface"), IS_STRING
))) {
531 PHP_HTTP_CURL_OPT(CURLOPT_INTERFACE
, Z_STRVAL_P(zoption
));
533 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("portrange"), IS_ARRAY
))) {
536 zend_hash_internal_pointer_reset(Z_ARRVAL_P(zoption
));
537 if (SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_P(zoption
), (void *) &prs
)) {
538 zend_hash_move_forward(Z_ARRVAL_P(zoption
));
539 if (SUCCESS
== zend_hash_get_current_data(Z_ARRVAL_P(zoption
), (void *) &pre
)) {
540 zval
*prs_cpy
= php_http_zsep(IS_LONG
, *prs
);
541 zval
*pre_cpy
= php_http_zsep(IS_LONG
, *pre
);
543 if (Z_LVAL_P(prs_cpy
) && Z_LVAL_P(pre_cpy
)) {
544 PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORT
, MIN(Z_LVAL_P(prs_cpy
), Z_LVAL_P(pre_cpy
)));
545 PHP_HTTP_CURL_OPT(CURLOPT_LOCALPORTRANGE
, labs(Z_LVAL_P(prs_cpy
)-Z_LVAL_P(pre_cpy
))+1L);
547 zval_ptr_dtor(&prs_cpy
);
548 zval_ptr_dtor(&pre_cpy
);
555 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("port"), IS_LONG
))) {
556 PHP_HTTP_CURL_OPT(CURLOPT_PORT
, Z_LVAL_P(zoption
));
559 /* RFC4007 zone_id */
560 #if PHP_HTTP_CURL_VERSION(7,19,0)
561 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("address_scope"), IS_LONG
))) {
562 PHP_HTTP_CURL_OPT(CURLOPT_ADDRESS_SCOPE
, Z_LVAL_P(zoption
));
567 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("httpauth"), IS_STRING
)) && Z_STRLEN_P(zoption
)) {
568 PHP_HTTP_CURL_OPT(CURLOPT_USERPWD
, Z_STRVAL_P(zoption
));
570 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("httpauthtype"), IS_LONG
))) {
571 PHP_HTTP_CURL_OPT(CURLOPT_HTTPAUTH
, Z_LVAL_P(zoption
));
574 /* redirects, defaults to 0 */
575 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("redirect"), IS_LONG
))) {
576 PHP_HTTP_CURL_OPT(CURLOPT_FOLLOWLOCATION
, Z_LVAL_P(zoption
) ? 1L : 0L);
577 PHP_HTTP_CURL_OPT(CURLOPT_MAXREDIRS
, Z_LVAL_P(zoption
));
578 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("unrestrictedauth"), IS_BOOL
))) {
579 PHP_HTTP_CURL_OPT(CURLOPT_UNRESTRICTED_AUTH
, Z_LVAL_P(zoption
));
581 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("postredir"), IS_BOOL
))) {
582 #if PHP_HTTP_CURL_VERSION(7,19,1)
583 PHP_HTTP_CURL_OPT(CURLOPT_POSTREDIR
, Z_BVAL_P(zoption
) ? 1L : 0L);
585 PHP_HTTP_CURL_OPT(CURLOPT_POST301
, Z_BVAL_P(zoption
) ? 1L : 0L);
590 /* retries, defaults to 0 */
591 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("retrycount"), IS_LONG
))) {
592 request
->_retry
.count
= Z_LVAL_P(zoption
);
593 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("retrydelay"), IS_DOUBLE
))) {
594 request
->_retry
.delay
= Z_DVAL_P(zoption
);
596 request
->_retry
.delay
= 0;
599 request
->_retry
.count
= 0;
603 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("referer"), IS_STRING
)) && Z_STRLEN_P(zoption
)) {
604 PHP_HTTP_CURL_OPT(CURLOPT_REFERER
, Z_STRVAL_P(zoption
));
607 /* useragent, default "PECL::HTTP/version (PHP/version)" */
608 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("useragent"), IS_STRING
))) {
609 /* allow to send no user agent, not even default one */
610 if (Z_STRLEN_P(zoption
)) {
611 PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT
, Z_STRVAL_P(zoption
));
613 PHP_HTTP_CURL_OPT(CURLOPT_USERAGENT
, NULL
);
618 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("resume"), IS_LONG
)) && (Z_LVAL_P(zoption
) > 0)) {
620 PHP_HTTP_CURL_OPT(CURLOPT_RESUME_FROM
, Z_LVAL_P(zoption
));
622 /* or range of kind array(array(0,499), array(100,1499)) */
623 else if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("range"), IS_ARRAY
)) && zend_hash_num_elements(Z_ARRVAL_P(zoption
))) {
624 HashPosition pos1
, pos2
;
625 zval
**rr
, **rb
, **re
;
628 php_http_buffer_init(&rs
);
629 FOREACH_VAL(pos1
, zoption
, rr
) {
630 if (Z_TYPE_PP(rr
) == IS_ARRAY
) {
631 zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(rr
), &pos2
);
632 if (SUCCESS
== zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr
), (void *) &rb
, &pos2
)) {
633 zend_hash_move_forward_ex(Z_ARRVAL_PP(rr
), &pos2
);
634 if (SUCCESS
== zend_hash_get_current_data_ex(Z_ARRVAL_PP(rr
), (void *) &re
, &pos2
)) {
635 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))) &&
636 ((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)))) {
637 zval
*rbl
= php_http_zsep(IS_LONG
, *rb
);
638 zval
*rel
= php_http_zsep(IS_LONG
, *re
);
640 if ((Z_LVAL_P(rbl
) >= 0) && (Z_LVAL_P(rel
) >= 0)) {
641 php_http_buffer_appendf(&rs
, "%ld-%ld,", Z_LVAL_P(rbl
), Z_LVAL_P(rel
));
651 if (PHP_HTTP_BUFFER_LEN(&rs
)) {
654 /* ditch last comma */
655 PHP_HTTP_BUFFER_VAL(&rs
)[PHP_HTTP_BUFFER_LEN(&rs
)-- -1] = '\0';
657 MAKE_STD_ZVAL(cached_range
);
658 ZVAL_STRINGL(cached_range
, PHP_HTTP_BUFFER_VAL(&rs
), PHP_HTTP_BUFFER_LEN(&rs
), 0);
659 PHP_HTTP_CURL_OPT(CURLOPT_RANGE
, Z_STRVAL_P(php_http_request_option_cache(request
, ZEND_STRS("range"), 0, cached_range
)));
660 zval_ptr_dtor(&cached_range
);
664 /* additional headers, array('name' => 'value') */
665 if (request
->_cache
.headers
) {
666 curl_slist_free_all(request
->_cache
.headers
);
667 request
->_cache
.headers
= NULL
;
669 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("headers"), IS_ARRAY
))) {
670 php_http_array_hashkey_t header_key
= php_http_array_hashkey_init(0);
673 php_http_buffer header
;
675 php_http_buffer_init(&header
);
676 FOREACH_KEYVAL(pos
, zoption
, header_key
, header_val
) {
677 if (header_key
.type
== HASH_KEY_IS_STRING
) {
678 zval
*header_cpy
= php_http_zsep(IS_STRING
, *header_val
);
680 if (!strcasecmp(header_key
.str
, "range")) {
684 php_http_buffer_appendf(&header
, "%s: %s", header_key
.str
, Z_STRVAL_P(header_cpy
));
685 php_http_buffer_fix(&header
);
686 request
->_cache
.headers
= curl_slist_append(request
->_cache
.headers
, PHP_HTTP_BUFFER_VAL(&header
));
687 php_http_buffer_reset(&header
);
689 zval_ptr_dtor(&header_cpy
);
692 php_http_buffer_dtor(&header
);
695 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("etag"), IS_STRING
)) && Z_STRLEN_P(zoption
)) {
696 zend_bool is_quoted
= !((Z_STRVAL_P(zoption
)[0] != '"') || (Z_STRVAL_P(zoption
)[Z_STRLEN_P(zoption
)-1] != '"'));
697 php_http_buffer header
;
699 php_http_buffer_init(&header
);
700 php_http_buffer_appendf(&header
, is_quoted
?"%s: %s":"%s: \"%s\"", range_req
?"If-Match":"If-None-Match", Z_STRVAL_P(zoption
));
701 php_http_buffer_fix(&header
);
702 request
->_cache
.headers
= curl_slist_append(request
->_cache
.headers
, PHP_HTTP_BUFFER_VAL(&header
));
703 php_http_buffer_dtor(&header
);
706 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("compress"), IS_BOOL
)) && Z_LVAL_P(zoption
)) {
707 request
->_cache
.headers
= curl_slist_append(request
->_cache
.headers
, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5");
709 PHP_HTTP_CURL_OPT(CURLOPT_HTTPHEADER
, request
->_cache
.headers
);
712 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("lastmodified"), IS_LONG
))) {
713 if (Z_LVAL_P(zoption
)) {
714 if (Z_LVAL_P(zoption
) > 0) {
715 PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE
, Z_LVAL_P(zoption
));
717 PHP_HTTP_CURL_OPT(CURLOPT_TIMEVALUE
, (long) PHP_HTTP_G
->env
.request
.time
+ Z_LVAL_P(zoption
));
719 PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION
, (long) (range_req
? CURL_TIMECOND_IFUNMODSINCE
: CURL_TIMECOND_IFMODSINCE
));
721 PHP_HTTP_CURL_OPT(CURLOPT_TIMECONDITION
, CURL_TIMECOND_NONE
);
725 /* cookies, array('name' => 'value') */
726 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("cookies"), IS_ARRAY
))) {
727 php_http_buffer_dtor(&request
->_cache
.cookies
);
728 if (zend_hash_num_elements(Z_ARRVAL_P(zoption
))) {
729 zval
*urlenc_cookies
= NULL
;
730 /* check whether cookies should not be urlencoded; default is to urlencode them */
731 if ((!(urlenc_cookies
= php_http_request_option(request
, options
, ZEND_STRS("encodecookies"), IS_BOOL
))) || Z_BVAL_P(urlenc_cookies
)) {
732 if (SUCCESS
== php_http_url_encode_hash_recursive(HASH_OF(zoption
), &request
->_cache
.cookies
, "; ", lenof("; "), NULL
, 0 TSRMLS_CC
)) {
733 php_http_buffer_fix(&request
->_cache
.cookies
);
734 PHP_HTTP_CURL_OPT(CURLOPT_COOKIE
, request
->_cache
.cookies
.data
);
738 php_http_array_hashkey_t cookie_key
= php_http_array_hashkey_init(0);
741 FOREACH_KEYVAL(pos
, zoption
, cookie_key
, cookie_val
) {
742 if (cookie_key
.type
== HASH_KEY_IS_STRING
) {
743 zval
*val
= php_http_zsep(IS_STRING
, *cookie_val
);
744 php_http_buffer_appendf(&request
->_cache
.cookies
, "%s=%s; ", cookie_key
.str
, Z_STRVAL_P(val
));
749 php_http_buffer_fix(&request
->_cache
.cookies
);
750 if (PHP_HTTP_BUFFER_LEN(&request
->_cache
.cookies
)) {
751 PHP_HTTP_CURL_OPT(CURLOPT_COOKIE
, PHP_HTTP_BUFFER_VAL(&request
->_cache
.cookies
));
757 /* don't load session cookies from cookiestore */
758 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("cookiesession"), IS_BOOL
)) && Z_BVAL_P(zoption
)) {
759 PHP_HTTP_CURL_OPT(CURLOPT_COOKIESESSION
, 1L);
762 /* cookiestore, read initial cookies from that file and store cookies back into that file */
763 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("cookiestore"), IS_STRING
))) {
764 if (Z_STRLEN_P(zoption
)) {
765 if (SUCCESS
!= php_check_open_basedir(Z_STRVAL_P(zoption
) TSRMLS_CC
)) {
769 if (storage
->cookiestore
) {
770 pefree(storage
->cookiestore
, 1);
772 storage
->cookiestore
= pestrndup(Z_STRVAL_P(zoption
), Z_STRLEN_P(zoption
), 1);
773 PHP_HTTP_CURL_OPT(CURLOPT_COOKIEFILE
, storage
->cookiestore
);
774 PHP_HTTP_CURL_OPT(CURLOPT_COOKIEJAR
, storage
->cookiestore
);
778 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("maxfilesize"), IS_LONG
))) {
779 PHP_HTTP_CURL_OPT(CURLOPT_MAXFILESIZE
, Z_LVAL_P(zoption
));
783 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("protocol"), IS_LONG
))) {
784 PHP_HTTP_CURL_OPT(CURLOPT_HTTP_VERSION
, Z_LVAL_P(zoption
));
787 /* timeout, defaults to 0 */
788 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("timeout"), IS_DOUBLE
))) {
789 PHP_HTTP_CURL_OPT(CURLOPT_TIMEOUT_MS
, (long)(Z_DVAL_P(zoption
)*1000));
791 /* connecttimeout, defaults to 0 */
792 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("connecttimeout"), IS_DOUBLE
))) {
793 PHP_HTTP_CURL_OPT(CURLOPT_CONNECTTIMEOUT_MS
, (long)(Z_DVAL_P(zoption
)*1000));
797 if ((zoption
= php_http_request_option(request
, options
, ZEND_STRS("ssl"), IS_ARRAY
))) {
798 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
802 FOREACH_KEYVAL(pos
, zoption
, key
, param
) {
803 if (key
.type
== HASH_KEY_IS_STRING
) {
804 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERT
, 0, 1);
805 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTTYPE
, 0, 0);
806 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLCERTPASSWD
, 0, 0);
808 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEY
, 0, 0);
809 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYTYPE
, 0, 0);
810 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLKEYPASSWD
, 0, 0);
812 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSLENGINE
, 0, 0);
813 PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSLVERSION
, 0);
815 PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYPEER
, 1);
816 PHP_HTTP_CURL_OPT_LONG(CURLOPT_SSL_VERIFYHOST
, 1);
817 PHP_HTTP_CURL_OPT_STRING(CURLOPT_SSL_CIPHER_LIST
, 1, 0);
819 PHP_HTTP_CURL_OPT_STRING(CURLOPT_CAINFO
, -3, 1);
820 PHP_HTTP_CURL_OPT_STRING(CURLOPT_CAPATH
, -3, 1);
821 PHP_HTTP_CURL_OPT_STRING(CURLOPT_RANDOM_FILE
, -3, 1);
822 PHP_HTTP_CURL_OPT_STRING(CURLOPT_EGDSOCKET
, -3, 1);
823 #if PHP_HTTP_CURL_VERSION(7,19,0)
824 PHP_HTTP_CURL_OPT_STRING(CURLOPT_ISSUERCERT
, -3, 1);
825 #if defined(PHP_HTTP_HAVE_OPENSSL)
826 PHP_HTTP_CURL_OPT_STRING(CURLOPT_CRLFILE
, -3, 1);
829 #if PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)
830 PHP_HTTP_CURL_OPT_LONG(CURLOPT_CERTINFO
, -3);
837 switch (request
->meth
) {
839 PHP_HTTP_CURL_OPT(CURLOPT_HTTPGET
, 1L);
843 PHP_HTTP_CURL_OPT(CURLOPT_NOBODY
, 1L);
847 PHP_HTTP_CURL_OPT(CURLOPT_POST
, 1L);
851 PHP_HTTP_CURL_OPT(CURLOPT_UPLOAD
, 1L);
855 const char *meth
= php_http_request_method_name(request
->meth
);
858 PHP_HTTP_CURL_OPT(CURLOPT_CUSTOMREQUEST
, meth
);
860 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST_METHOD
, "Unsupported request method: %d (%s)", request
->meth
, request
->url
);
867 /* attach request body */
868 if (request
->body
&& (request
->meth
!= PHP_HTTP_GET
) && (request
->meth
!= PHP_HTTP_HEAD
) && (request
->meth
!= PHP_HTTP_OPTIONS
)) {
869 if (1 || request
->meth
== PHP_HTTP_PUT
) {
870 /* PUT/UPLOAD _needs_ READDATA */
871 PHP_HTTP_CURL_OPT(CURLOPT_IOCTLDATA
, request
);
872 PHP_HTTP_CURL_OPT(CURLOPT_READDATA
, request
);
873 PHP_HTTP_CURL_OPT(CURLOPT_INFILESIZE
, php_http_message_body_size(request
->body
));
876 //PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDS, request->body->real->data);
877 PHP_HTTP_CURL_OPT(CURLOPT_POSTFIELDSIZE
, php_http_message_body_size(request
->body
));
884 PHP_HTTP_API
void php_http_request_exec(php_http_request_t
*request
)
888 TSRMLS_FETCH_FROM_CTX(request
->ts
);
891 if (CURLE_OK
!= (result
= curl_easy_perform(request
->ch
))) {
892 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "%s; %s (%s)", curl_easy_strerror(result
), php_http_request_storage_get(request
->ch
)->errorbuffer
, request
->url
);
894 add_property_long(EG(exception
), "curlCode", result
);
897 if (request
->_retry
.count
> tries
++) {
899 case CURLE_COULDNT_RESOLVE_PROXY
:
900 case CURLE_COULDNT_RESOLVE_HOST
:
901 case CURLE_COULDNT_CONNECT
:
902 case CURLE_WRITE_ERROR
:
903 case CURLE_READ_ERROR
:
904 case CURLE_OPERATION_TIMEDOUT
:
905 case CURLE_SSL_CONNECT_ERROR
:
906 case CURLE_GOT_NOTHING
:
907 case CURLE_SSL_ENGINE_SETFAILED
:
908 case CURLE_SEND_ERROR
:
909 case CURLE_RECV_ERROR
:
910 case CURLE_SSL_ENGINE_INITFAILED
:
911 case CURLE_LOGIN_DENIED
:
912 if (request
->_retry
.delay
>= PHP_HTTP_DIFFSEC
) {
913 php_http_sleep(request
->_retry
.delay
);
923 static size_t php_http_curl_read_callback(void *data
, size_t len
, size_t n
, void *ctx
)
925 php_http_request_t
*request
= (php_http_request_t
*) ctx
;
926 TSRMLS_FETCH_FROM_CTX(request
->ts
);
929 return php_stream_read(php_http_message_body_stream(request
->body
), data
, len
* n
);
934 static int php_http_curl_progress_callback(void *ctx
, double dltotal
, double dlnow
, double ultotal
, double ulnow
)
936 php_http_request_t
*request
= (php_http_request_t
*) ctx
;
938 request
->_progress
.state
.dl
.total
= dltotal
;
939 request
->_progress
.state
.dl
.now
= dlnow
;
940 request
->_progress
.state
.ul
.total
= ultotal
;
941 request
->_progress
.state
.ul
.now
= ulnow
;
943 if (request
->_progress
.callback
) {
945 TSRMLS_FETCH_FROM_CTX(request
->ts
);
950 MAKE_STD_ZVAL(param
);
952 add_assoc_double(param
, "dltotal", request
->_progress
.state
.dl
.total
);
953 add_assoc_double(param
, "dlnow", request
->_progress
.state
.dl
.now
);
954 add_assoc_double(param
, "ultotal", request
->_progress
.state
.ul
.total
);
955 add_assoc_double(param
, "ulnow", request
->_progress
.state
.ul
.now
);
957 with_error_handling(EH_NORMAL
, NULL
) {
958 request
->_progress
.in_cb
= 1;
959 call_user_function(EG(function_table
), NULL
, request
->_progress
.callback
, &retval
, 1, ¶m TSRMLS_CC
);
960 request
->_progress
.in_cb
= 0;
961 } end_error_handling();
963 zval_ptr_dtor(¶m
);
970 static curlioerr
php_http_curl_ioctl_callback(CURL
*ch
, curliocmd cmd
, void *ctx
)
972 php_http_request_t
*request
= (php_http_request_t
*) ctx
;
973 TSRMLS_FETCH_FROM_CTX(request
->ts
);
975 if (cmd
!= CURLIOCMD_RESTARTREAD
) {
976 return CURLIOE_UNKNOWNCMD
;
980 if (SUCCESS
== php_stream_rewind(php_http_message_body_stream(request
->body
))) {
985 return CURLIOE_FAILRESTART
;
988 static int php_http_curl_raw_callback(CURL
*ch
, curl_infotype type
, char *data
, size_t length
, void *ctx
)
990 php_http_request_t
*request
= (php_http_request_t
*) ctx
;
994 case CURLINFO_HEADER_IN
:
995 case CURLINFO_DATA_IN
:
996 case CURLINFO_HEADER_OUT
:
997 case CURLINFO_DATA_OUT
:
998 php_http_buffer_append(request
->parser
.buf
, data
, length
);
999 if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE
== php_http_message_parser_parse(request
->parser
.ctx
, request
->parser
.buf
, 0, &request
->parser
.msg
)) {
1010 const char _sym
[] = "><><><";
1012 for (fprintf(stderr
, "%c ", _sym
[type
-1]); length
--; data
++) {
1013 fprintf(stderr
, PHP_HTTP_IS_CTYPE(print
, *data
)?"%c":"\\x%02X", (int) *data
);
1014 if (*data
== '\n' && length
) {
1015 fprintf(stderr
, "\n%c ", _sym
[type
-1]);
1018 fprintf(stderr
, "\n");
1020 fprintf(stderr
, "# %s", data
);
1028 static inline zval
*php_http_request_option(php_http_request_t
*r
, HashTable
*options
, char *key
, size_t keylen
, int type
)
1030 TSRMLS_FETCH_FROM_CTX(r
->ts
);
1034 ulong h
= zend_hash_func(key
, keylen
);
1036 if (SUCCESS
== zend_hash_quick_find(options
, key
, keylen
, h
, (void *) &zoption
)) {
1037 zval
*option
, *cached
;
1039 option
= php_http_zsep(type
, *zoption
);
1040 cached
= php_http_request_option_cache(r
, key
, keylen
, h
, option
);
1042 zval_ptr_dtor(&option
);
1050 static inline zval
*php_http_request_option_cache(php_http_request_t
*r
, char *key
, size_t keylen
, ulong h
, zval
*opt
)
1052 TSRMLS_FETCH_FROM_CTX(r
->ts
);
1056 zend_hash_quick_update(&r
->_cache
.options
, key
, keylen
, h
, &opt
, sizeof(zval
*), NULL
);
1058 zend_hash_update(&r
->_cache
.options
, key
, keylen
, &opt
, sizeof(zval
*), NULL
);
1064 static inline int php_http_request_cookies_enabled(php_http_request_t
*request
) {
1065 php_http_request_storage_t
*st
;
1067 if (request
->ch
&& (st
= php_http_request_storage_get(request
->ch
)) && st
->cookiestore
) {
1068 /* cookies are enabled */
1076 #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequest, method, 0, req_args)
1077 #define PHP_HTTP_EMPTY_ARGS(method) PHP_HTTP_EMPTY_ARGS_EX(HttpRequest, method, 0)
1078 #define PHP_HTTP_REQUEST_ME(method, visibility) PHP_ME(HttpRequest, method, PHP_HTTP_ARGS(HttpRequest, method), visibility)
1079 #define PHP_HTTP_REQUEST_ALIAS(method, func) PHP_HTTP_STATIC_ME_ALIAS(method, func, PHP_HTTP_ARGS(HttpRequest, method))
1080 #define PHP_HTTP_REQUEST_MALIAS(me, al, vis) ZEND_FENTRY(me, ZEND_MN(HttpRequest_##al), PHP_HTTP_ARGS(HttpRequest, al), vis)
1082 PHP_HTTP_BEGIN_ARGS(__construct
, 0)
1083 PHP_HTTP_ARG_VAL(url
, 0)
1084 PHP_HTTP_ARG_VAL(method
, 0)
1085 PHP_HTTP_ARG_VAL(options
, 0)
1088 PHP_HTTP_BEGIN_ARGS(factory
, 0)
1089 PHP_HTTP_ARG_VAL(url
, 0)
1090 PHP_HTTP_ARG_VAL(method
, 0)
1091 PHP_HTTP_ARG_VAL(options
, 0)
1092 PHP_HTTP_ARG_VAL(class_name
, 0)
1095 PHP_HTTP_EMPTY_ARGS(getOptions
);
1096 PHP_HTTP_BEGIN_ARGS(setOptions
, 0)
1097 PHP_HTTP_ARG_VAL(options
, 0)
1100 PHP_HTTP_EMPTY_ARGS(getSslOptions
);
1101 PHP_HTTP_BEGIN_ARGS(setSslOptions
, 0)
1102 PHP_HTTP_ARG_VAL(ssl_options
, 0)
1105 PHP_HTTP_BEGIN_ARGS(addSslOptions
, 0)
1106 PHP_HTTP_ARG_VAL(ssl_optins
, 0)
1109 PHP_HTTP_EMPTY_ARGS(getHeaders
);
1110 PHP_HTTP_BEGIN_ARGS(setHeaders
, 0)
1111 PHP_HTTP_ARG_VAL(headers
, 0)
1114 PHP_HTTP_BEGIN_ARGS(addHeaders
, 1)
1115 PHP_HTTP_ARG_VAL(headers
, 0)
1118 PHP_HTTP_EMPTY_ARGS(getCookies
);
1119 PHP_HTTP_BEGIN_ARGS(setCookies
, 0)
1120 PHP_HTTP_ARG_VAL(cookies
, 0)
1123 PHP_HTTP_BEGIN_ARGS(addCookies
, 1)
1124 PHP_HTTP_ARG_VAL(cookies
, 0)
1127 PHP_HTTP_EMPTY_ARGS(enableCookies
);
1128 PHP_HTTP_BEGIN_ARGS(resetCookies
, 0)
1129 PHP_HTTP_ARG_VAL(session_only
, 0)
1131 PHP_HTTP_EMPTY_ARGS(flushCookies
);
1133 PHP_HTTP_EMPTY_ARGS(getUrl
);
1134 PHP_HTTP_BEGIN_ARGS(setUrl
, 1)
1135 PHP_HTTP_ARG_VAL(url
, 0)
1138 PHP_HTTP_EMPTY_ARGS(getMethod
);
1139 PHP_HTTP_BEGIN_ARGS(setMethod
, 1)
1140 PHP_HTTP_ARG_VAL(request_method
, 0)
1143 PHP_HTTP_EMPTY_ARGS(getContentType
);
1144 PHP_HTTP_BEGIN_ARGS(setContentType
, 1)
1145 PHP_HTTP_ARG_VAL(content_type
, 0)
1148 PHP_HTTP_EMPTY_ARGS(getQueryData
);
1149 PHP_HTTP_BEGIN_ARGS(setQueryData
, 0)
1150 PHP_HTTP_ARG_VAL(query_data
, 0)
1153 PHP_HTTP_BEGIN_ARGS(addQueryData
, 1)
1154 PHP_HTTP_ARG_VAL(query_data
, 0)
1158 PHP_HTTP_EMPTY_ARGS(getBody
);
1159 PHP_HTTP_BEGIN_ARGS(setBody
, 0)
1160 PHP_HTTP_ARG_OBJ(http
\\message
\\Body
, body
, 0)
1163 PHP_HTTP_BEGIN_ARGS(addBody
, 1)
1164 PHP_HTTP_ARG_OBJ(http
\\message
\\Body
, body
, 0)
1167 PHP_HTTP_BEGIN_ARGS(getResponseCookies
, 0)
1168 PHP_HTTP_ARG_VAL(flags
, 0)
1169 PHP_HTTP_ARG_VAL(allowed_extras
, 0)
1172 PHP_HTTP_EMPTY_ARGS(getResponseBody
);
1173 PHP_HTTP_EMPTY_ARGS(getResponseCode
);
1174 PHP_HTTP_EMPTY_ARGS(getResponseStatus
);
1175 PHP_HTTP_BEGIN_ARGS(getResponseInfo
, 0)
1176 PHP_HTTP_ARG_VAL(name
, 0)
1179 PHP_HTTP_BEGIN_ARGS(getResponseHeader
, 0)
1180 PHP_HTTP_ARG_VAL(header_name
, 0)
1183 PHP_HTTP_EMPTY_ARGS(getMessageClass
);
1184 PHP_HTTP_BEGIN_ARGS(setMessageClass
, 1)
1185 PHP_HTTP_ARG_VAL(message_class_name
, 0)
1188 PHP_HTTP_EMPTY_ARGS(getResponseMessage
);
1189 PHP_HTTP_EMPTY_ARGS(getRawResponseMessage
);
1190 PHP_HTTP_EMPTY_ARGS(getRequestMessage
);
1191 PHP_HTTP_EMPTY_ARGS(getRawRequestMessage
);
1192 PHP_HTTP_EMPTY_ARGS(getHistory
);
1193 PHP_HTTP_EMPTY_ARGS(clearHistory
);
1194 PHP_HTTP_EMPTY_ARGS(send
);
1196 PHP_HTTP_BEGIN_ARGS(get
, 1)
1197 PHP_HTTP_ARG_VAL(url
, 0)
1198 PHP_HTTP_ARG_VAL(options
, 0)
1199 PHP_HTTP_ARG_VAL(info
, 1)
1202 PHP_HTTP_BEGIN_ARGS(head
, 1)
1203 PHP_HTTP_ARG_VAL(url
, 0)
1204 PHP_HTTP_ARG_VAL(options
, 0)
1205 PHP_HTTP_ARG_VAL(info
, 1)
1208 PHP_HTTP_BEGIN_ARGS(postData
, 2)
1209 PHP_HTTP_ARG_VAL(url
, 0)
1210 PHP_HTTP_ARG_VAL(data
, 0)
1211 PHP_HTTP_ARG_VAL(options
, 0)
1212 PHP_HTTP_ARG_VAL(info
, 1)
1215 PHP_HTTP_BEGIN_ARGS(postFields
, 2)
1216 PHP_HTTP_ARG_VAL(url
, 0)
1217 PHP_HTTP_ARG_VAL(data
, 0)
1218 PHP_HTTP_ARG_VAL(options
, 0)
1219 PHP_HTTP_ARG_VAL(info
, 1)
1222 PHP_HTTP_BEGIN_ARGS(putData
, 2)
1223 PHP_HTTP_ARG_VAL(url
, 0)
1224 PHP_HTTP_ARG_VAL(data
, 0)
1225 PHP_HTTP_ARG_VAL(options
, 0)
1226 PHP_HTTP_ARG_VAL(info
, 1)
1229 PHP_HTTP_BEGIN_ARGS(putFile
, 2)
1230 PHP_HTTP_ARG_VAL(url
, 0)
1231 PHP_HTTP_ARG_VAL(file
, 0)
1232 PHP_HTTP_ARG_VAL(options
, 0)
1233 PHP_HTTP_ARG_VAL(info
, 1)
1236 PHP_HTTP_BEGIN_ARGS(putStream
, 2)
1237 PHP_HTTP_ARG_VAL(url
, 0)
1238 PHP_HTTP_ARG_VAL(stream
, 0)
1239 PHP_HTTP_ARG_VAL(options
, 0)
1240 PHP_HTTP_ARG_VAL(info
, 1)
1243 PHP_HTTP_BEGIN_ARGS(methodRegister
, 1)
1244 PHP_HTTP_ARG_VAL(method_name
, 0)
1247 PHP_HTTP_BEGIN_ARGS(methodUnregister
, 1)
1248 PHP_HTTP_ARG_VAL(method
, 0)
1251 PHP_HTTP_BEGIN_ARGS(methodName
, 1)
1252 PHP_HTTP_ARG_VAL(method_id
, 0)
1255 PHP_HTTP_BEGIN_ARGS(methodExists
, 1)
1256 PHP_HTTP_ARG_VAL(method
, 0)
1259 #ifdef HAVE_CURL_FORMGET
1260 PHP_HTTP_BEGIN_ARGS(encodeBody
, 2)
1261 PHP_HTTP_ARG_VAL(fields
, 0)
1262 PHP_HTTP_ARG_VAL(files
, 0)
1266 zend_class_entry
*php_http_request_class_entry
;
1267 zend_function_entry php_http_request_method_entry
[] = {
1268 PHP_HTTP_REQUEST_ME(__construct
, ZEND_ACC_PUBLIC
|ZEND_ACC_CTOR
)
1270 PHP_HTTP_REQUEST_ME(setOptions
, ZEND_ACC_PUBLIC
)
1271 PHP_HTTP_REQUEST_ME(getOptions
, ZEND_ACC_PUBLIC
)
1272 PHP_HTTP_REQUEST_ME(setSslOptions
, ZEND_ACC_PUBLIC
)
1273 PHP_HTTP_REQUEST_ME(getSslOptions
, ZEND_ACC_PUBLIC
)
1274 PHP_HTTP_REQUEST_ME(addSslOptions
, ZEND_ACC_PUBLIC
)
1276 PHP_HTTP_REQUEST_ME(addHeaders
, ZEND_ACC_PUBLIC
)
1277 PHP_HTTP_REQUEST_ME(getHeaders
, ZEND_ACC_PUBLIC
)
1278 PHP_HTTP_REQUEST_ME(setHeaders
, ZEND_ACC_PUBLIC
)
1280 PHP_HTTP_REQUEST_ME(addCookies
, ZEND_ACC_PUBLIC
)
1281 PHP_HTTP_REQUEST_ME(getCookies
, ZEND_ACC_PUBLIC
)
1282 PHP_HTTP_REQUEST_ME(setCookies
, ZEND_ACC_PUBLIC
)
1284 PHP_HTTP_REQUEST_ME(enableCookies
, ZEND_ACC_PUBLIC
)
1285 PHP_HTTP_REQUEST_ME(resetCookies
, ZEND_ACC_PUBLIC
)
1286 PHP_HTTP_REQUEST_ME(flushCookies
, ZEND_ACC_PUBLIC
)
1288 PHP_HTTP_REQUEST_ME(setMethod
, ZEND_ACC_PUBLIC
)
1289 PHP_HTTP_REQUEST_ME(getMethod
, ZEND_ACC_PUBLIC
)
1291 PHP_HTTP_REQUEST_ME(setUrl
, ZEND_ACC_PUBLIC
)
1292 PHP_HTTP_REQUEST_ME(getUrl
, ZEND_ACC_PUBLIC
)
1294 PHP_HTTP_REQUEST_ME(setContentType
, ZEND_ACC_PUBLIC
)
1295 PHP_HTTP_REQUEST_ME(getContentType
, ZEND_ACC_PUBLIC
)
1297 PHP_HTTP_REQUEST_ME(setQueryData
, ZEND_ACC_PUBLIC
)
1298 PHP_HTTP_REQUEST_ME(getQueryData
, ZEND_ACC_PUBLIC
)
1299 PHP_HTTP_REQUEST_ME(addQueryData
, ZEND_ACC_PUBLIC
)
1301 PHP_HTTP_REQUEST_ME(setBody
, ZEND_ACC_PUBLIC
)
1302 PHP_HTTP_REQUEST_ME(getBody
, ZEND_ACC_PUBLIC
)
1303 PHP_HTTP_REQUEST_ME(addBody
, ZEND_ACC_PUBLIC
)
1305 PHP_HTTP_REQUEST_ME(send
, ZEND_ACC_PUBLIC
)
1307 PHP_HTTP_REQUEST_ME(getResponseHeader
, ZEND_ACC_PUBLIC
)
1308 PHP_HTTP_REQUEST_ME(getResponseCookies
, ZEND_ACC_PUBLIC
)
1309 PHP_HTTP_REQUEST_ME(getResponseCode
, ZEND_ACC_PUBLIC
)
1310 PHP_HTTP_REQUEST_ME(getResponseStatus
, ZEND_ACC_PUBLIC
)
1311 PHP_HTTP_REQUEST_ME(getResponseBody
, ZEND_ACC_PUBLIC
)
1312 PHP_HTTP_REQUEST_ME(getResponseInfo
, ZEND_ACC_PUBLIC
)
1313 PHP_HTTP_REQUEST_ME(getResponseMessage
, ZEND_ACC_PUBLIC
)
1314 PHP_HTTP_REQUEST_ME(getRequestMessage
, ZEND_ACC_PUBLIC
)
1315 PHP_HTTP_REQUEST_ME(getHistory
, ZEND_ACC_PUBLIC
)
1316 PHP_HTTP_REQUEST_ME(clearHistory
, ZEND_ACC_PUBLIC
)
1318 PHP_HTTP_REQUEST_ME(getMessageClass
, ZEND_ACC_PUBLIC
)
1319 PHP_HTTP_REQUEST_ME(setMessageClass
, ZEND_ACC_PUBLIC
)
1321 EMPTY_FUNCTION_ENTRY
1323 static zend_object_handlers php_http_request_object_handlers
;
1325 zend_object_value
php_http_request_object_new(zend_class_entry
*ce TSRMLS_DC
)
1327 return php_http_request_object_new_ex(ce
, NULL
, NULL
);
1330 zend_object_value
php_http_request_object_new_ex(zend_class_entry
*ce
, CURL
*ch
, php_http_request_object_t
**ptr TSRMLS_DC
)
1332 zend_object_value ov
;
1333 php_http_request_object_t
*o
;
1335 o
= ecalloc(1, sizeof(php_http_request_object_t
));
1336 zend_object_std_init((zend_object
*) o
, ce TSRMLS_CC
);
1337 object_properties_init((zend_object
*) o
, ce
);
1339 o
->request
= php_http_request_init(NULL
, ch
, 0, NULL TSRMLS_CC
);
1345 ov
.handle
= zend_objects_store_put(o
, NULL
, php_http_request_object_free
, NULL TSRMLS_CC
);
1346 ov
.handlers
= &php_http_request_object_handlers
;
1351 zend_object_value
php_http_request_object_clone(zval
*this_ptr TSRMLS_DC
)
1353 zend_object_value new_ov
;
1354 php_http_request_object_t
*new_obj
, *old_obj
= zend_object_store_get_object(this_ptr TSRMLS_CC
);
1356 new_ov
= php_http_request_object_new_ex(old_obj
->zo
.ce
, NULL
, &new_obj TSRMLS_CC
);
1357 if (old_obj
->request
->ch
) {
1358 php_http_curl_init(php_http_curl_copy(old_obj
->request
->ch
), new_obj
->request TSRMLS_CC
);
1361 zend_objects_clone_members(&new_obj
->zo
, new_ov
, &old_obj
->zo
, Z_OBJ_HANDLE_P(this_ptr
) TSRMLS_CC
);
1367 void php_http_request_object_free(void *object TSRMLS_DC
)
1369 php_http_request_object_t
*o
= (php_http_request_object_t
*) object
;
1371 php_http_request_free(&o
->request
);
1372 zend_object_std_dtor((zend_object
*) o TSRMLS_CC
);
1376 static inline void php_http_request_object_check_request_content_type(zval
*this_ptr TSRMLS_DC
)
1378 zval
*ctype
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("contentType"), 0 TSRMLS_CC
);
1380 if (Z_STRLEN_P(ctype
)) {
1381 zval
**headers
, *opts
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1383 if ( (Z_TYPE_P(opts
) == IS_ARRAY
) &&
1384 (SUCCESS
== zend_hash_find(Z_ARRVAL_P(opts
), ZEND_STRS("headers"), (void *) &headers
)) &&
1385 (Z_TYPE_PP(headers
) == IS_ARRAY
)) {
1388 /* only override if not already set */
1389 if ((SUCCESS
!= zend_hash_find(Z_ARRVAL_PP(headers
), ZEND_STRS("Content-Type"), (void *) &ct_header
))) {
1390 add_assoc_stringl(*headers
, "Content-Type", Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
1392 /* or not a string, zero length string or a string of spaces */
1393 if ((Z_TYPE_PP(ct_header
) != IS_STRING
) || !Z_STRLEN_PP(ct_header
)) {
1394 add_assoc_stringl(*headers
, "Content-Type", Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
1396 int i
, only_space
= 1;
1398 /* check for spaces only */
1399 for (i
= 0; i
< Z_STRLEN_PP(ct_header
); ++i
) {
1400 if (!PHP_HTTP_IS_CTYPE(space
, Z_STRVAL_PP(ct_header
)[i
])) {
1406 add_assoc_stringl(*headers
, "Content-Type", Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
1412 MAKE_STD_ZVAL(headers
);
1413 array_init(headers
);
1414 add_assoc_stringl(headers
, "Content-Type", Z_STRVAL_P(ctype
), Z_STRLEN_P(ctype
), 1);
1415 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "addheaders", NULL
, headers
);
1416 zval_ptr_dtor(&headers
);
1421 static inline zend_object_value
php_http_request_object_message(zval
*this_ptr
, php_http_message_t
*msg TSRMLS_DC
)
1423 zend_object_value ov
;
1424 zval
*zcn
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("messageClass"), 0 TSRMLS_CC
);
1425 zend_class_entry
*class_entry
;
1428 && (class_entry
= zend_fetch_class(Z_STRVAL_P(zcn
), Z_STRLEN_P(zcn
), 0 TSRMLS_CC
))
1429 && (SUCCESS
== php_http_new(&ov
, class_entry
, (php_http_new_t
) php_http_message_object_new_ex
, php_http_message_class_entry
, msg
, NULL TSRMLS_CC
))) {
1432 return php_http_message_object_new_ex(php_http_message_class_entry
, msg
, NULL TSRMLS_CC
);
1436 STATUS
php_http_request_object_requesthandler(php_http_request_object_t
*obj
, zval
*this_ptr TSRMLS_DC
)
1438 STATUS status
= SUCCESS
;
1439 zval
*zurl
, *zmeth
, *zbody
, *zqdata
, *zoptions
;
1440 php_http_message_body_t
*body
= NULL
;
1441 php_url
*tmp
, qdu
= {0};
1443 php_http_request_reset(obj
->request
);
1444 PHP_HTTP_CHECK_CURL_INIT(obj
->request
->ch
, php_http_curl_init(NULL
, obj
->request TSRMLS_CC
), return FAILURE
);
1445 php_http_request_object_check_request_content_type(getThis() TSRMLS_CC
);
1447 zmeth
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("method"), 0 TSRMLS_CC
);
1448 obj
->request
->meth
= Z_LVAL_P(zmeth
);
1450 zurl
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("url"), 0 TSRMLS_CC
);
1451 zqdata
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), 0 TSRMLS_CC
);
1452 if (Z_STRLEN_P(zqdata
)) {
1453 qdu
.query
= Z_STRVAL_P(zqdata
);
1455 php_http_url(0, tmp
= php_url_parse(Z_STRVAL_P(zurl
)), &qdu
, NULL
, &obj
->request
->url
, NULL TSRMLS_CC
);
1458 zbody
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("requestBody"), 0 TSRMLS_CC
);
1459 if (Z_TYPE_P(zbody
) == IS_OBJECT
) {
1460 body
= ((php_http_message_body_object_t
*)zend_object_store_get_object(zbody TSRMLS_CC
))->body
;
1462 obj
->request
->body
= body
;
1464 zoptions
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1465 php_http_request_prepare(obj
->request
, Z_ARRVAL_P(zoptions
));
1467 /* check if there's a onProgress method and add it as progress callback if one isn't already set */
1468 if (zend_hash_exists(&Z_OBJCE_P(getThis())->function_table
, ZEND_STRS("onprogress"))) {
1471 if ((Z_TYPE_P(zoptions
) != IS_ARRAY
)
1472 || (SUCCESS
!= zend_hash_find(Z_ARRVAL_P(zoptions
), ZEND_STRS("onprogress"), (void *) &entry
)
1473 || (!zend_is_callable(*entry
, 0, NULL TSRMLS_CC
)))) {
1476 Z_ADDREF_P(getThis());
1477 add_next_index_zval(pcb
, getThis());
1478 add_next_index_stringl(pcb
, "onprogress", lenof("onprogress"), 1);
1479 php_http_request_set_progress_callback(obj
->request
, pcb
);
1480 zval_ptr_dtor(&pcb
);
1487 STATUS
php_http_request_object_responsehandler(php_http_request_object_t
*obj
, zval
*this_ptr TSRMLS_DC
)
1489 STATUS ret
= SUCCESS
;
1491 php_http_message_t
*msg
;
1493 /* always fetch info */
1494 MAKE_STD_ZVAL(info
);
1496 php_http_request_info(obj
->request
, Z_ARRVAL_P(info
));
1497 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseInfo"), info TSRMLS_CC
);
1498 zval_ptr_dtor(&info
);
1500 /* update history * /
1501 if (i_zend_is_true(zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("recordHistory"), 0 TSRMLS_CC))) {
1502 zval *new_hist, *old_hist = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC);
1503 zend_object_value ov = php_http_request_object_message(getThis(), obj->request->message_parser.message TSRMLS_CC);
1505 MAKE_STD_ZVAL(new_hist);
1506 ZVAL_OBJVAL(new_hist, ov, 0);
1508 if (Z_TYPE_P(old_hist) == IS_OBJECT) {
1509 php_http_message_object_prepend(new_hist, old_hist, 0 TSRMLS_CC);
1512 zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), new_hist TSRMLS_CC);
1513 zval_ptr_dtor(&new_hist);
1516 // if ((msg = obj->request->_current.request)) {
1517 // /* update request message */
1520 // MAKE_STD_ZVAL(message);
1521 // ZVAL_OBJVAL(message, php_http_request_object_message(getThis(), msg TSRMLS_CC), 1);
1522 // zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("requestMessage"), message TSRMLS_CC);
1524 // fprintf(stderr, "RESPONSE MESSAGE: %p\n", obj->request->parser.msg);
1525 if ((msg
= obj
->request
->parser
.msg
)) {
1526 /* update properties with response info */
1529 zend_update_property_long(php_http_request_class_entry
, getThis(), ZEND_STRL("responseCode"), msg
->http
.info
.response
.code TSRMLS_CC
);
1530 zend_update_property_string(php_http_request_class_entry
, getThis(), ZEND_STRL("responseStatus"), STR_PTR(msg
->http
.info
.response
.status
) TSRMLS_CC
);
1532 MAKE_STD_ZVAL(message
);
1533 ZVAL_OBJVAL(message
, php_http_request_object_message(getThis(), msg TSRMLS_CC
), 0);
1534 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), message TSRMLS_CC
);
1535 zval_ptr_dtor(&message
);
1536 obj
->request
->parser
.msg
= php_http_message_init(NULL
, 0 TSRMLS_CC
);
1538 /* update properties with empty values */
1541 MAKE_STD_ZVAL(znull
);
1543 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), znull TSRMLS_CC
);
1544 zval_ptr_dtor(&znull
);
1546 zend_update_property_long(php_http_request_class_entry
, getThis(), ZEND_STRL("responseCode"), 0 TSRMLS_CC
);
1547 zend_update_property_string(php_http_request_class_entry
, getThis(), ZEND_STRL("responseStatus"), "" TSRMLS_CC
);
1550 php_http_request_set_progress_callback(obj
->request
, NULL
);
1552 if (!EG(exception
) && zend_hash_exists(&Z_OBJCE_P(getThis())->function_table
, ZEND_STRS("onfinish"))) {
1555 MAKE_STD_ZVAL(param
);
1556 ZVAL_BOOL(param
, ret
== SUCCESS
);
1557 with_error_handling(EH_NORMAL
, NULL
) {
1558 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "onfinish", NULL
, param
);
1559 } end_error_handling();
1560 zval_ptr_dtor(¶m
);
1566 static int apply_pretty_key(void *pDest
, int num_args
, va_list args
, zend_hash_key
*hash_key
)
1568 if (hash_key
->arKey
&& hash_key
->nKeyLength
> 1) {
1569 hash_key
->h
= zend_hash_func(php_http_pretty_key(hash_key
->arKey
, hash_key
->nKeyLength
- 1, 1, 0), hash_key
->nKeyLength
);
1571 return ZEND_HASH_APPLY_KEEP
;
1574 static inline void php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAMETERS
, char *key
, size_t len
, int overwrite
, int prettify_keys
)
1576 zval
*old_opts
, *new_opts
, *opts
= NULL
, **entry
= NULL
;
1578 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a/!", &opts
)) {
1582 MAKE_STD_ZVAL(new_opts
);
1583 array_init(new_opts
);
1584 old_opts
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1585 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
1586 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
1589 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(new_opts
), key
, len
, (void *) &entry
)) {
1591 zend_hash_clean(Z_ARRVAL_PP(entry
));
1593 if (opts
&& zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
1595 array_copy(Z_ARRVAL_P(opts
), Z_ARRVAL_PP(entry
));
1597 array_join(Z_ARRVAL_P(opts
), Z_ARRVAL_PP(entry
), 0, prettify_keys
? ARRAY_JOIN_PRETTIFY
: 0);
1601 if (prettify_keys
) {
1602 zend_hash_apply_with_arguments(Z_ARRVAL_P(opts
) TSRMLS_CC
, apply_pretty_key
, 0, NULL
);
1605 add_assoc_zval_ex(new_opts
, key
, len
, opts
);
1607 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
1608 zval_ptr_dtor(&new_opts
);
1613 static inline void php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAMETERS
, char *key
, size_t len
)
1615 if (SUCCESS
== zend_parse_parameters_none()) {
1616 zval
*opts
, **options
;
1618 opts
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1619 array_init(return_value
);
1621 if ( (Z_TYPE_P(opts
) == IS_ARRAY
) &&
1622 (SUCCESS
== zend_hash_find(Z_ARRVAL_P(opts
), key
, len
, (void *) &options
))) {
1623 convert_to_array(*options
);
1624 array_copy(Z_ARRVAL_PP(options
), Z_ARRVAL_P(return_value
));
1630 PHP_METHOD(HttpRequest
, __construct
)
1632 char *url_str
= NULL
;
1635 zval
*options
= NULL
;
1637 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
1638 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|sla!", &url_str
, &url_len
, &meth
, &options
)) {
1640 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("url"), url_str
, url_len TSRMLS_CC
);
1643 zend_update_property_long(php_http_request_class_entry
, getThis(), ZEND_STRL("method"), meth TSRMLS_CC
);
1646 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "setoptions", NULL
, options
);
1649 } end_error_handling();
1652 PHP_METHOD(HttpRequest
, setOptions
)
1654 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
1656 zval
*opts
= NULL
, *old_opts
, *new_opts
, *add_opts
, **opt
;
1658 if (SUCCESS
!= zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|a!/", &opts
)) {
1662 MAKE_STD_ZVAL(new_opts
);
1663 array_init(new_opts
);
1665 if (!opts
|| !zend_hash_num_elements(Z_ARRVAL_P(opts
))) {
1666 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
1667 zval_ptr_dtor(&new_opts
);
1671 MAKE_STD_ZVAL(add_opts
);
1672 array_init(add_opts
);
1673 /* some options need extra attention -- thus cannot use array_merge() directly */
1674 FOREACH_KEYVAL(pos
, opts
, key
, opt
) {
1675 if (key
.type
== HASH_KEY_IS_STRING
) {
1676 #define KEYMATCH(k, s) ((sizeof(s)==k.len) && !strcasecmp(k.str, s))
1677 if (KEYMATCH(key
, "headers")) {
1678 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "addheaders", NULL
, *opt
);
1679 } else if (KEYMATCH(key
, "cookies")) {
1680 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "addcookies", NULL
, *opt
);
1681 } else if (KEYMATCH(key
, "ssl")) {
1682 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "addssloptions", NULL
, *opt
);
1683 } else if (KEYMATCH(key
, "url") || KEYMATCH(key
, "uri")) {
1684 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "seturl", NULL
, *opt
);
1685 } else if (KEYMATCH(key
, "method")) {
1686 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "setmethod", NULL
, *opt
);
1687 } else if (KEYMATCH(key
, "flushcookies")) {
1688 if (i_zend_is_true(*opt
)) {
1689 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1691 php_http_request_flush_cookies(obj
->request
);
1693 } else if (KEYMATCH(key
, "resetcookies")) {
1694 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1696 php_http_request_reset_cookies(obj
->request
, (zend_bool
) i_zend_is_true(*opt
));
1697 } else if (KEYMATCH(key
, "enablecookies")) {
1698 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1700 php_http_request_enable_cookies(obj
->request
);
1701 } else if (KEYMATCH(key
, "recordHistory")) {
1702 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("recordHistory"), *opt TSRMLS_CC
);
1703 } else if (KEYMATCH(key
, "messageClass")) {
1704 zend_call_method_with_1_params(&getThis(), Z_OBJCE_P(getThis()), NULL
, "setmessageclass", NULL
, *opt
);
1705 } else if (Z_TYPE_PP(opt
) == IS_NULL
) {
1706 old_opts
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1707 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
1708 zend_hash_del(Z_ARRVAL_P(old_opts
), key
.str
, key
.len
);
1712 add_assoc_zval_ex(add_opts
, key
.str
, key
.len
, *opt
);
1717 old_opts
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), 0 TSRMLS_CC
);
1718 if (Z_TYPE_P(old_opts
) == IS_ARRAY
) {
1719 array_copy(Z_ARRVAL_P(old_opts
), Z_ARRVAL_P(new_opts
));
1721 array_join(Z_ARRVAL_P(add_opts
), Z_ARRVAL_P(new_opts
), 0, 0);
1722 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("options"), new_opts TSRMLS_CC
);
1723 zval_ptr_dtor(&new_opts
);
1724 zval_ptr_dtor(&add_opts
);
1731 PHP_METHOD(HttpRequest
, getOptions
)
1733 if (SUCCESS
== zend_parse_parameters_none()) {
1734 RETURN_PROP(php_http_request_class_entry
, "options");
1739 PHP_METHOD(HttpRequest
, setSslOptions
)
1741 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("ssl"), 1, 0);
1744 PHP_METHOD(HttpRequest
, addSslOptions
)
1746 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("ssl"), 0, 0);
1749 PHP_METHOD(HttpRequest
, getSslOptions
)
1751 php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("ssl"));
1754 PHP_METHOD(HttpRequest
, addHeaders
)
1756 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("headers"), 0, 1);
1759 PHP_METHOD(HttpRequest
, setHeaders
)
1761 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("headers"), 1, 1);
1764 PHP_METHOD(HttpRequest
, getHeaders
)
1766 php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("headers"));
1769 PHP_METHOD(HttpRequest
, setCookies
)
1771 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("cookies"), 1, 0);
1774 PHP_METHOD(HttpRequest
, addCookies
)
1776 php_http_request_object_set_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("cookies"), 0, 0);
1779 PHP_METHOD(HttpRequest
, getCookies
)
1781 php_http_request_object_get_options_subr(INTERNAL_FUNCTION_PARAM_PASSTHRU
, ZEND_STRS("cookies"));
1784 PHP_METHOD(HttpRequest
, enableCookies
)
1786 if (SUCCESS
== zend_parse_parameters_none()){
1787 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1789 RETURN_SUCCESS(php_http_request_enable_cookies(obj
->request
));
1794 PHP_METHOD(HttpRequest
, resetCookies
)
1796 zend_bool session_only
= 0;
1798 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|b", &session_only
)) {
1799 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1800 RETURN_SUCCESS(php_http_request_reset_cookies(obj
->request
, session_only
));
1805 PHP_METHOD(HttpRequest
, flushCookies
)
1807 if (SUCCESS
== zend_parse_parameters_none()) {
1808 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
1810 RETURN_SUCCESS(php_http_request_flush_cookies(obj
->request
));
1815 PHP_METHOD(HttpRequest
, setUrl
)
1817 char *url_str
= NULL
;
1820 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &url_len
, &url_len
)) {
1821 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("url"), url_str
, url_len TSRMLS_CC
);
1827 PHP_METHOD(HttpRequest
, getUrl
)
1829 if (SUCCESS
== zend_parse_parameters_none()) {
1830 RETURN_PROP(php_http_request_class_entry
, "url");
1835 PHP_METHOD(HttpRequest
, setMethod
)
1839 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "l", &meth
)) {
1840 zend_update_property_long(php_http_request_class_entry
, getThis(), ZEND_STRL("method"), meth TSRMLS_CC
);
1846 PHP_METHOD(HttpRequest
, getMethod
)
1848 if (SUCCESS
== zend_parse_parameters_none()) {
1849 RETURN_PROP(php_http_request_class_entry
, "method");
1854 PHP_METHOD(HttpRequest
, setContentType
)
1859 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &ctype
, &ct_len
)) {
1861 PHP_HTTP_CHECK_CONTENT_TYPE(ctype
, RETURN_FALSE
);
1863 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("contentType"), ctype
, ct_len TSRMLS_CC
);
1869 PHP_METHOD(HttpRequest
, getContentType
)
1871 if (SUCCESS
== zend_parse_parameters_none()) {
1872 RETURN_PROP(php_http_request_class_entry
, "contentType");
1877 PHP_METHOD(HttpRequest
, setQueryData
)
1881 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "z!", &qdata
)) {
1882 if ((!qdata
) || Z_TYPE_P(qdata
) == IS_NULL
) {
1883 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), "", 0 TSRMLS_CC
);
1884 } else if ((Z_TYPE_P(qdata
) == IS_ARRAY
) || (Z_TYPE_P(qdata
) == IS_OBJECT
)) {
1885 char *query_data_str
= NULL
;
1886 size_t query_data_len
;
1888 if (SUCCESS
!= php_http_url_encode_hash(HASH_OF(qdata
), 0, NULL
, 0, &query_data_str
, &query_data_len TSRMLS_CC
)) {
1892 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), query_data_str
, query_data_len TSRMLS_CC
);
1893 efree(query_data_str
);
1895 zval
*data
= php_http_zsep(IS_STRING
, qdata
);
1897 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), Z_STRVAL_P(data
), Z_STRLEN_P(data
) TSRMLS_CC
);
1898 zval_ptr_dtor(&data
);
1905 PHP_METHOD(HttpRequest
, getQueryData
)
1907 if (SUCCESS
== zend_parse_parameters_none()) {
1908 RETURN_PROP(php_http_request_class_entry
, "queryData");
1913 PHP_METHOD(HttpRequest
, addQueryData
)
1917 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "a/", &qdata
)) {
1918 char *query_data_str
= NULL
;
1919 size_t query_data_len
= 0;
1920 zval
*old_qdata
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), 0 TSRMLS_CC
);
1922 if (SUCCESS
!= php_http_url_encode_hash(HASH_OF(qdata
), 1, Z_STRVAL_P(old_qdata
), Z_STRLEN_P(old_qdata
), &query_data_str
, &query_data_len TSRMLS_CC
)) {
1926 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("queryData"), query_data_str
, query_data_len TSRMLS_CC
);
1927 efree(query_data_str
);
1935 PHP_METHOD(HttpRequest
, setBody
)
1939 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|O!", &body
, php_http_message_body_class_entry
)) {
1940 if (body
&& Z_TYPE_P(body
) != IS_NULL
) {
1941 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("requestBody"), body TSRMLS_CC
);
1943 zend_update_property_null(php_http_request_class_entry
, getThis(), ZEND_STRL("requestBody") TSRMLS_CC
);
1950 PHP_METHOD(HttpRequest
, addBody
)
1954 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "O", &new_body
, php_http_message_body_class_entry
)) {
1955 zval
*old_body
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("requestBody"), 0 TSRMLS_CC
);
1957 if (Z_TYPE_P(old_body
) == IS_OBJECT
) {
1958 php_http_message_body_object_t
*old_obj
= zend_object_store_get_object(old_body TSRMLS_CC
);
1959 php_http_message_body_object_t
*new_obj
= zend_object_store_get_object(new_body TSRMLS_CC
);
1961 php_http_message_body_to_callback(old_obj
->body
, (php_http_pass_callback_t
) php_http_message_body_append
, new_obj
->body
, 0, 0);
1963 zend_update_property(php_http_request_class_entry
, getThis(), ZEND_STRL("requestBody"), new_body TSRMLS_CC
);
1970 PHP_METHOD(HttpRequest
, getBody
)
1972 if (SUCCESS
== zend_parse_parameters_none()) {
1973 RETURN_PROP(php_http_request_class_entry
, "requestBody");
1978 PHP_METHOD(HttpRequest
, getResponseHeader
)
1981 char *header_name
= NULL
;
1984 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &header_name
, &header_len
)) {
1985 zval
*message
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC
);
1987 if (Z_TYPE_P(message
) == IS_OBJECT
) {
1988 php_http_message_object_t
*msg
= zend_object_store_get_object(message TSRMLS_CC
);
1991 if ((header
= php_http_message_header(msg
->message
, header_name
, header_len
+ 1, 0))) {
1992 RETURN_ZVAL(header
, 1, 1);
1995 array_init(return_value
);
1996 zend_hash_copy(Z_ARRVAL_P(return_value
), &msg
->message
->hdrs
, (copy_ctor_func_t
) zval_add_ref
, NULL
, sizeof(zval
*));
2004 PHP_METHOD(HttpRequest
, getResponseCookies
)
2007 zval
*allowed_extras_array
= NULL
;
2009 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|la!", &flags
, &allowed_extras_array
)) {
2011 php_http_array_hashkey_t key
= php_http_array_hashkey_init(0);
2012 char **allowed_extras
= NULL
;
2013 zval
**header
= NULL
, **entry
= NULL
, *message
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC
);
2014 HashPosition pos
, pos1
, pos2
;
2016 if (Z_TYPE_P(message
) == IS_OBJECT
) {
2017 php_http_message_object_t
*msg
= zend_object_store_get_object(message TSRMLS_CC
);
2019 array_init(return_value
);
2021 if (allowed_extras_array
) {
2022 allowed_extras
= ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array
)) + 1, sizeof(char *));
2023 FOREACH_VAL(pos
, allowed_extras_array
, entry
) {
2024 zval
*data
= php_http_zsep(IS_STRING
, *entry
);
2025 allowed_extras
[i
++] = estrndup(Z_STRVAL_P(data
), Z_STRLEN_P(data
));
2026 zval_ptr_dtor(&data
);
2030 FOREACH_HASH_KEYVAL(pos1
, &msg
->message
->hdrs
, key
, header
) {
2031 if (key
.type
== HASH_KEY_IS_STRING
&& !strcasecmp(key
.str
, "Set-Cookie")) {
2032 php_http_cookie_list_t
*list
;
2034 if (Z_TYPE_PP(header
) == IS_ARRAY
) {
2035 zval
**single_header
;
2037 FOREACH_VAL(pos2
, *header
, single_header
) {
2038 zval
*data
= php_http_zsep(IS_STRING
, *single_header
);
2040 if ((list
= php_http_cookie_list_parse(NULL
, Z_STRVAL_P(data
), flags
, allowed_extras TSRMLS_CC
))) {
2043 MAKE_STD_ZVAL(cookie
);
2044 ZVAL_OBJVAL(cookie
, php_http_cookie_object_new_ex(php_http_cookie_class_entry
, list
, NULL TSRMLS_CC
), 0);
2045 add_next_index_zval(return_value
, cookie
);
2047 zval_ptr_dtor(&data
);
2050 zval
*data
= php_http_zsep(IS_STRING
, *header
);
2051 if ((list
= php_http_cookie_list_parse(NULL
, Z_STRVAL_P(data
), flags
, allowed_extras TSRMLS_CC
))) {
2054 MAKE_STD_ZVAL(cookie
);
2055 ZVAL_OBJVAL(cookie
, php_http_cookie_object_new_ex(php_http_cookie_class_entry
, list
, NULL TSRMLS_CC
), 0);
2056 add_next_index_zval(return_value
, cookie
);
2058 zval_ptr_dtor(&data
);
2063 if (allowed_extras
) {
2064 for (i
= 0; allowed_extras
[i
]; ++i
) {
2065 efree(allowed_extras
[i
]);
2067 efree(allowed_extras
);
2076 PHP_METHOD(HttpRequest
, getResponseBody
)
2078 if (SUCCESS
== zend_parse_parameters_none()) {
2079 zval
*message
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC
);
2080 zval
*body
= zend_read_property(php_http_message_class_entry
, message
, ZEND_STRL("body"), 0 TSRMLS_CC
);
2082 RETURN_ZVAL(body
, 1, 0);
2087 PHP_METHOD(HttpRequest
, getResponseCode
)
2089 if (SUCCESS
== zend_parse_parameters_none()) {
2090 RETURN_PROP(php_http_request_class_entry
, "responseCode");
2095 PHP_METHOD(HttpRequest
, getResponseStatus
)
2097 if (SUCCESS
== zend_parse_parameters_none()) {
2098 RETURN_PROP(php_http_request_class_entry
, "responseStatus");
2103 PHP_METHOD(HttpRequest
, getResponseInfo
)
2105 char *info_name
= NULL
;
2108 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "|s", &info_name
, &info_len
)) {
2109 zval
**infop
, *info
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseInfo"), 0 TSRMLS_CC
);
2111 if (Z_TYPE_P(info
) != IS_ARRAY
) {
2115 if (info_len
&& info_name
) {
2116 if (SUCCESS
== zend_hash_find(Z_ARRVAL_P(info
), php_http_pretty_key(info_name
, info_len
, 0, 0), info_len
+ 1, (void *) &infop
)) {
2117 RETURN_ZVAL(*infop
, 1, 0);
2119 php_http_error(HE_NOTICE
, PHP_HTTP_E_INVALID_PARAM
, "Could not find response info named %s", info_name
);
2123 RETURN_ZVAL(info
, 1, 0);
2129 PHP_METHOD(HttpRequest
, getResponseMessage
)
2131 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
2132 if (SUCCESS
== zend_parse_parameters_none()) {
2133 zval
*message
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC
);
2135 if (Z_TYPE_P(message
) == IS_OBJECT
) {
2136 RETVAL_OBJECT(message
, 1);
2138 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "HttpRequest does not contain a response message");
2141 } end_error_handling();
2144 PHP_METHOD(HttpRequest
, getRequestMessage
)
2146 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
2147 if (SUCCESS
== zend_parse_parameters_none()) {
2148 zval
*message
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("requestMessage"), 0 TSRMLS_CC
);
2150 if (Z_TYPE_P(message
) == IS_OBJECT
) {
2151 RETVAL_OBJECT(message
, 1);
2153 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "HttpRequest does not contain a request message");
2156 } end_error_handling();
2159 PHP_METHOD(HttpRequest
, getHistory
)
2161 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
2162 if (SUCCESS
== zend_parse_parameters_none()) {
2163 zval
*hist
= zend_read_property(php_http_request_class_entry
, getThis(), ZEND_STRL("history"), 0 TSRMLS_CC
);
2165 if (Z_TYPE_P(hist
) == IS_OBJECT
) {
2166 RETVAL_OBJECT(hist
, 1);
2168 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "The history is empty");
2171 } end_error_handling();
2174 PHP_METHOD(HttpRequest
, clearHistory
)
2176 if (SUCCESS
== zend_parse_parameters_none()) {
2177 zend_update_property_null(php_http_request_class_entry
, getThis(), ZEND_STRL("history") TSRMLS_CC
);
2183 PHP_METHOD(HttpRequest
, getMessageClass
)
2185 if (SUCCESS
== zend_parse_parameters_none()) {
2186 RETURN_PROP(php_http_request_class_entry
, "messageClass");
2191 PHP_METHOD(HttpRequest
, setMessageClass
)
2196 if (SUCCESS
== zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC
, "s", &cn
, &cl
)) {
2197 zend_update_property_stringl(php_http_request_class_entry
, getThis(), ZEND_STRL("messageClass"), cn
, cl TSRMLS_CC
);
2201 PHP_METHOD(HttpRequest
, send
)
2205 with_error_handling(EH_THROW
, PHP_HTTP_EX_CE(runtime
)) {
2206 if (SUCCESS
== zend_parse_parameters_none()) {
2207 php_http_request_object_t
*obj
= zend_object_store_get_object(getThis() TSRMLS_CC
);
2210 php_http_error(HE_WARNING
, PHP_HTTP_E_RUNTIME
, "Cannot perform HttpRequest::send() while attached to an HttpRequestPool");
2211 } else if (SUCCESS
== php_http_request_object_requesthandler(obj
, getThis() TSRMLS_CC
)) {
2212 php_http_request_exec(obj
->request
);
2213 if (SUCCESS
== php_http_request_object_responsehandler(obj
, getThis() TSRMLS_CC
)) {
2214 RETVAL_PROP(php_http_request_class_entry
, "responseMessage");
2216 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Failed to handle response");
2219 php_http_error(HE_WARNING
, PHP_HTTP_E_REQUEST
, "Failed to handle request");
2222 } end_error_handling();
2225 PHP_MINIT_FUNCTION(http_request
)
2227 #ifdef PHP_HTTP_NEED_OPENSSL_TSL
2228 /* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */
2229 if (!CRYPTO_get_id_callback()) {
2230 int i
, c
= CRYPTO_num_locks();
2232 php_http_openssl_tsl
= malloc(c
* sizeof(MUTEX_T
));
2234 for (i
= 0; i
< c
; ++i
) {
2235 php_http_openssl_tsl
[i
] = tsrm_mutex_alloc();
2238 CRYPTO_set_id_callback(php_http_openssl_thread_id
);
2239 CRYPTO_set_locking_callback(php_http_openssl_thread_lock
);
2242 #ifdef PHP_HTTP_NEED_GNUTLS_TSL
2243 gcry_control(GCRYCTL_SET_THREAD_CBS
, &php_http_gnutls_tsl
);
2246 if (CURLE_OK
!= curl_global_init(CURL_GLOBAL_ALL
)) {
2250 if (SUCCESS
!= php_http_persistent_handle_provide(ZEND_STRL("http_request"), safe_curl_init
, safe_curl_dtor
, safe_curl_copy
)) {
2254 PHP_HTTP_REGISTER_CLASS(http
, Request
, http_request
, php_http_object_class_entry
, 0);
2255 php_http_request_class_entry
->create_object
= php_http_request_object_new
;
2256 memcpy(&php_http_request_object_handlers
, zend_get_std_object_handlers(), sizeof(zend_object_handlers
));
2257 php_http_request_object_handlers
.clone_obj
= php_http_request_object_clone
;
2259 zend_declare_property_null(php_http_request_class_entry
, ZEND_STRL("options"), ZEND_ACC_PRIVATE TSRMLS_CC
);
2260 zend_declare_property_null(php_http_request_class_entry
, ZEND_STRL("responseInfo"), ZEND_ACC_PRIVATE TSRMLS_CC
);
2261 zend_declare_property_null(php_http_request_class_entry
, ZEND_STRL("responseMessage"), ZEND_ACC_PRIVATE TSRMLS_CC
);
2262 zend_declare_property_long(php_http_request_class_entry
, ZEND_STRL("responseCode"), 0, ZEND_ACC_PRIVATE TSRMLS_CC
);
2263 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("responseStatus"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2264 zend_declare_property_null(php_http_request_class_entry
, ZEND_STRL("requestMessage"), ZEND_ACC_PRIVATE TSRMLS_CC
);
2265 zend_declare_property_long(php_http_request_class_entry
, ZEND_STRL("method"), PHP_HTTP_GET
, ZEND_ACC_PRIVATE TSRMLS_CC
);
2266 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("url"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2267 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("contentType"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2268 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("requestBody"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2269 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("queryData"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2270 zend_declare_property_null(php_http_request_class_entry
, ZEND_STRL("history"), ZEND_ACC_PRIVATE TSRMLS_CC
);
2271 zend_declare_property_bool(php_http_request_class_entry
, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC TSRMLS_CC
);
2272 zend_declare_property_string(php_http_request_class_entry
, ZEND_STRL("messageClass"), "", ZEND_ACC_PRIVATE TSRMLS_CC
);
2275 * HTTP Protocol Version Constants
2277 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("VERSION_1_0"), CURL_HTTP_VERSION_1_0 TSRMLS_CC
);
2278 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("VERSION_1_1"), CURL_HTTP_VERSION_1_1 TSRMLS_CC
);
2279 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("VERSION_NONE"), CURL_HTTP_VERSION_NONE TSRMLS_CC
); /* to be removed */
2280 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("VERSION_ANY"), CURL_HTTP_VERSION_NONE TSRMLS_CC
);
2283 * SSL Version Constants
2285 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("SSL_VERSION_TLSv1"), CURL_SSLVERSION_TLSv1 TSRMLS_CC
);
2286 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("SSL_VERSION_SSLv2"), CURL_SSLVERSION_SSLv2 TSRMLS_CC
);
2287 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("SSL_VERSION_SSLv3"), CURL_SSLVERSION_SSLv3 TSRMLS_CC
);
2288 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("SSL_VERSION_ANY"), CURL_SSLVERSION_DEFAULT TSRMLS_CC
);
2291 * DNS IPvX resolving
2293 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("IPRESOLVE_V4"), CURL_IPRESOLVE_V4 TSRMLS_CC
);
2294 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("IPRESOLVE_V6"), CURL_IPRESOLVE_V6 TSRMLS_CC
);
2295 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("IPRESOLVE_ANY"), CURL_IPRESOLVE_WHATEVER TSRMLS_CC
);
2300 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_BASIC"), CURLAUTH_BASIC TSRMLS_CC
);
2301 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_DIGEST"), CURLAUTH_DIGEST TSRMLS_CC
);
2302 #if PHP_HTTP_CURL_VERSION(7,19,3)
2303 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_DIGEST_IE"), CURLAUTH_DIGEST_IE TSRMLS_CC
);
2305 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_NTLM"), CURLAUTH_NTLM TSRMLS_CC
);
2306 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_GSSNEG"), CURLAUTH_GSSNEGOTIATE TSRMLS_CC
);
2307 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("AUTH_ANY"), CURLAUTH_ANY TSRMLS_CC
);
2310 * Proxy Type Constants
2312 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_SOCKS4"), CURLPROXY_SOCKS4 TSRMLS_CC
);
2313 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_SOCKS4A"), CURLPROXY_SOCKS5 TSRMLS_CC
);
2314 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_SOCKS5_HOSTNAME"), CURLPROXY_SOCKS5 TSRMLS_CC
);
2315 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_SOCKS5"), CURLPROXY_SOCKS5 TSRMLS_CC
);
2316 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_HTTP"), CURLPROXY_HTTP TSRMLS_CC
);
2317 # if PHP_HTTP_CURL_VERSION(7,19,4)
2318 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("PROXY_HTTP_1_0"), CURLPROXY_HTTP_1_0 TSRMLS_CC
);
2322 * Post Redirection Constants
2324 #if PHP_HTTP_CURL_VERSION(7,19,1)
2325 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("POSTREDIR_301"), CURL_REDIR_POST_301 TSRMLS_CC
);
2326 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("POSTREDIR_302"), CURL_REDIR_POST_302 TSRMLS_CC
);
2327 zend_declare_class_constant_long(php_http_request_class_entry
, ZEND_STRL("POSTREDIR_ALL"), CURL_REDIR_POST_ALL TSRMLS_CC
);
2333 PHP_MSHUTDOWN_FUNCTION(http_request
)
2335 curl_global_cleanup();
2336 #ifdef PHP_HTTP_NEED_OPENSSL_TSL
2337 if (php_http_openssl_tsl
) {
2338 int i
, c
= CRYPTO_num_locks();
2340 CRYPTO_set_id_callback(NULL
);
2341 CRYPTO_set_locking_callback(NULL
);
2343 for (i
= 0; i
< c
; ++i
) {
2344 tsrm_mutex_free(php_http_openssl_tsl
[i
]);
2347 free(php_http_openssl_tsl
);
2348 php_http_openssl_tsl
= NULL
;
2359 * vim600: noet sw=4 ts=4 fdm=marker
2360 * vim<600: noet sw=4 ts=4