mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00

This adds support for `CURLOPT_DEBUGFUNCTION`[^1] Curl option to set a
custom callback that gets called with debug information during the
lifetime of a Curl request.
The callback gets called with the `CurlHandle` object, an integer
containing the type of the debug message, and a string containing the
debug message. The callback may get called multiple times with the
same message type during a request.
PHP already uses `CURLOPT_DEBUGFUNCTION` functionality to internally
to expose a Curl option named `CURLINFO_HEADER_OUT`.
However,`CURLINFO_HEADER_OUT` is not a "real" Curl option supported
by libcurl. Back in 2006, `CURLINFO_HEADER_OUT` was added[^2] as
a Curl option by using the debug-callback feature. Git history does
not run that back to show why `CURLINFO_HEADER_OUT` was added as a
Curl option, and why the other debug types (such as
`CURLINFO_HEADER_IN` were not added as Curl options, but this seems
to be a historical artifact when we added features without trying
to be close to libcurl options.
This approach has a few issues:
1. `CURLINFO_HEADER_OUT` is not an actual Curl option supported by
upstream libcurl.
2. All of the Curl options have `CURLOPT_` prefix, and `CURLINFO_HEADER_OUT`
is the only Curl "option" that uses the `CURLINFO` prefix. This exception
is, however, noted[^3] in docs.
3. When `CURLINFO_HEADER_OUT` is set, the `CURLOPT_VERBOSE` is also implicitly
set. This was reported[^4] to bugs.php.net, but the bug is marked as wontfix.
This commit adds support for `CURLOPT_DEBUGFUNCTION`. It extends the existing
`curl_debug` callback to store the header-in information if it encounters
a debug message with `CURLINFO_HEADER_OUT`. In all cases, if a callable
is set, it gets called.
`CURLOPT_DEBUGFUNCTION` intends to replace `CURLINFO_HEADER_OUT` Curl
option as a versatile alternative that can also be used to extract
other debug information such as SSL data, text information messages,
incoming headers, as well as headers sent out (which `CURLINFO_HEADER_OUT`
makes available).
The callables are allowed to throw exceptions, but the return values are
ignored.
`CURLOPT_DEBUGFUNCTION` requires `CURLOPT_VERBOSE` enabled, and setting
`CURLOPT_DEBUGFUNCTION` does _not_ implicitly enable `CURLOPT_VERBOSE`.
If the `CURLOPT_DEBUGFUNCTION` option is set, setting `CURLINFO_HEADER_OUT`
throws a `ValueError` exception. Setting `CURLOPT_DEBUGFUNCTION` _after_
enabling `CURLINFO_HEADER_OUT` is allowed. Technically, it is possible
for both functionality (calling user-provided callback _and_ storing
header-out data) is possible, setting `CURLINFO_HEADER_OUT` is not
allowed to encourage the use of `CURLOPT_DEBUGFUNCTION` function.
This commit also adds the rest of the `CURLINFO_` constants used as
the `type` integer value in `CURLOPT_DEBUGFUNCTION` callback.
---
[^1]: [cur.se - CURLOPT_DEBUGFUNCTION](https://curl.se/libcurl/c/CURLOPT_DEBUGFUNCTION.html)
[^2]: [`5f25d80`](5f25d80d10
)
[^3]: [curl_setopt doc mentioning `CURLINFO_` prefix is intentional](https://www.php.net/manual/en/function.curl-setopt.php#:~:text=prefix%20is%20intentional)
[^4]: [bugs.php.net - `CURLOPT_VERBOSE` does not work with `CURLINFO_HEADER_OUT`](https://bugs.php.net/bug.php?id=65348)
159 lines
4.5 KiB
C
159 lines
4.5 KiB
C
/*
|
|
+----------------------------------------------------------------------+
|
|
| Copyright (c) The PHP Group |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| https://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author: Sterling Hughes <sterling@php.net> |
|
|
| Wez Furlong <wez@thebrainroom.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef _PHP_CURL_PRIVATE_H
|
|
#define _PHP_CURL_PRIVATE_H
|
|
|
|
#include "php_curl.h"
|
|
|
|
#define PHP_CURL_DEBUG 0
|
|
|
|
#include "php_version.h"
|
|
#define PHP_CURL_VERSION PHP_VERSION
|
|
|
|
#include <curl/curl.h>
|
|
#include <curl/multi.h>
|
|
|
|
#define CURLOPT_RETURNTRANSFER 19913
|
|
#define CURLOPT_BINARYTRANSFER 19914 /* For Backward compatibility */
|
|
#define PHP_CURL_STDOUT 0
|
|
#define PHP_CURL_FILE 1
|
|
#define PHP_CURL_USER 2
|
|
#define PHP_CURL_DIRECT 3
|
|
#define PHP_CURL_RETURN 4
|
|
#define PHP_CURL_IGNORE 7
|
|
|
|
#define SAVE_CURL_ERROR(__handle, __err) \
|
|
do { (__handle)->err.no = (int) __err; } while (0)
|
|
|
|
PHP_MINIT_FUNCTION(curl);
|
|
PHP_MSHUTDOWN_FUNCTION(curl);
|
|
PHP_MINFO_FUNCTION(curl);
|
|
|
|
typedef struct {
|
|
zend_fcall_info_cache fcc;
|
|
FILE *fp;
|
|
smart_str buf;
|
|
int method;
|
|
zval stream;
|
|
} php_curl_write;
|
|
|
|
typedef struct {
|
|
zend_fcall_info_cache fcc;
|
|
FILE *fp;
|
|
zend_resource *res;
|
|
int method;
|
|
zval stream;
|
|
} php_curl_read;
|
|
|
|
typedef struct {
|
|
php_curl_write *write;
|
|
php_curl_write *write_header;
|
|
php_curl_read *read;
|
|
zval std_err;
|
|
zend_fcall_info_cache progress;
|
|
zend_fcall_info_cache xferinfo;
|
|
zend_fcall_info_cache fnmatch;
|
|
zend_fcall_info_cache debug;
|
|
#if LIBCURL_VERSION_NUM >= 0x075000 /* Available since 7.80.0 */
|
|
zend_fcall_info_cache prereq;
|
|
#endif
|
|
#if LIBCURL_VERSION_NUM >= 0x075400 /* Available since 7.84.0 */
|
|
zend_fcall_info_cache sshhostkey;
|
|
#endif
|
|
} php_curl_handlers;
|
|
|
|
struct _php_curl_error {
|
|
char str[CURL_ERROR_SIZE + 1];
|
|
int no;
|
|
};
|
|
|
|
struct _php_curl_send_headers {
|
|
zend_string *str;
|
|
};
|
|
|
|
struct _php_curl_free {
|
|
zend_llist post;
|
|
zend_llist stream;
|
|
HashTable *slist;
|
|
};
|
|
|
|
typedef struct {
|
|
CURL *cp;
|
|
php_curl_handlers handlers;
|
|
struct _php_curl_free *to_free;
|
|
struct _php_curl_send_headers header;
|
|
struct _php_curl_error err;
|
|
bool in_callback;
|
|
uint32_t* clone;
|
|
zval postfields;
|
|
/* For CURLOPT_PRIVATE */
|
|
zval private_data;
|
|
/* CurlShareHandle object set using CURLOPT_SHARE. */
|
|
struct _php_curlsh *share;
|
|
zend_object std;
|
|
} php_curl;
|
|
|
|
#define CURLOPT_SAFE_UPLOAD -1
|
|
|
|
typedef struct {
|
|
zend_fcall_info_cache server_push;
|
|
} php_curlm_handlers;
|
|
|
|
typedef struct {
|
|
CURLM *multi;
|
|
zend_llist easyh;
|
|
php_curlm_handlers handlers;
|
|
struct {
|
|
int no;
|
|
} err;
|
|
zend_object std;
|
|
} php_curlm;
|
|
|
|
typedef struct _php_curlsh {
|
|
CURLSH *share;
|
|
struct {
|
|
int no;
|
|
} err;
|
|
zend_object std;
|
|
} php_curlsh;
|
|
|
|
php_curl *init_curl_handle_into_zval(zval *curl);
|
|
void init_curl_handle(php_curl *ch);
|
|
void _php_curl_cleanup_handle(php_curl *);
|
|
void _php_curl_multi_cleanup_list(void *data);
|
|
void _php_curl_verify_handlers(php_curl *ch, bool reporterror);
|
|
void _php_setup_easy_copy_handlers(php_curl *ch, php_curl *source);
|
|
|
|
static inline php_curl *curl_from_obj(zend_object *obj) {
|
|
return (php_curl *)((char *)(obj) - XtOffsetOf(php_curl, std));
|
|
}
|
|
|
|
#define Z_CURL_P(zv) curl_from_obj(Z_OBJ_P(zv))
|
|
|
|
static inline php_curlsh *curl_share_from_obj(zend_object *obj) {
|
|
return (php_curlsh *)((char *)(obj) - XtOffsetOf(php_curlsh, std));
|
|
}
|
|
|
|
#define Z_CURL_SHARE_P(zv) curl_share_from_obj(Z_OBJ_P(zv))
|
|
|
|
void curl_multi_register_handlers(void);
|
|
void curl_share_register_handlers(void);
|
|
void curlfile_register_class(void);
|
|
zend_result curl_cast_object(zend_object *obj, zval *result, int type);
|
|
|
|
#endif /* _PHP_CURL_PRIVATE_H */
|