package.xml 0000644 0001750 0000144 00000072155 12667772426 012074 0 ustar mike users
pecl_http
pecl.php.net
Extended HTTP Support
This HTTP extension aims to provide a convenient and powerful
set of functionality for one of PHPs major applications.
It eases handling of HTTP urls, headers and messages, provides
means for negotiation of a client's preferred content type,
language and charset, as well as a convenient way to send any
arbitrary data with caching and resuming capabilities.
It provides powerful request functionality with support for
parallel requests.
Documentation:
https://mdref.m6w6.name/http
Code Coverage:
http://dev.iworks.at/ext-http/lcov/ext/http/
Michael Wallner
mike
mike@php.net
yes
2016-03-09
3.0.1
3.0.0
stable
stable
BSD-2-Clause
* Fix php-bug #71719: Buffer overflow in HTTP url parsing functions (Mike, rc0r)
* Fix gh-issue #28: Possible null pointer dereference in php_http_url_mod() (rc0r)
* Fix gh-issue #21: Fix PHP7 config.w32 (Jan Ehrhardt)
* Fix gh-issue #20: setSslOptions notice with curl 7.43 (Mike, Vitaliy Demidov)
7.0.0
1.4.1
raphf
pecl.php.net
2.0.0dev
raphf
propro
pecl.php.net
2.0.0dev
propro
hash
iconv
http
pecl_http-3.0.1/src/php_http_api.h 0000644 0001750 0000144 00000007655 12667772426 016020 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_API_H
#define PHP_HTTP_API_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifndef PHP_WIN32
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef PHP_WIN32
# define PHP_HTTP_API __declspec(dllexport)
#elif defined(__GNUC__) && __GNUC__ >= 4
# define PHP_HTTP_API extern __attribute__ ((visibility("default")))
#else
# define PHP_HTTP_API extern
#endif
#if (defined(HAVE_ICONV) || defined(PHP_HTTP_HAVE_EXT_ICONV)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_ICONV))
# define PHP_HTTP_HAVE_ICONV
#endif
#if (defined(HAVE_HASH_EXT) || defined(PHP_HTTP_HAVE_EXT_HASH)) && (PHP_HTTP_SHARED_DEPS || !defined(COMPILE_DL_HASH)) && defined(PHP_HTTP_HAVE_PHP_HASH_H)
# define PHP_HTTP_HAVE_HASH
#endif
#include
#ifdef PHP_WIN32
# define CURL_STATICLIB
# include
#else
# ifdef HAVE_NETDB_H
# include
# endif
# ifdef HAVE_UNISTD_H
# include
# endif
#endif
#if defined(HAVE_WCHAR_H) && defined(HAVE_WCTYPE_H) && defined(HAVE_ISWALNUM) && (defined(HAVE_MBRTOWC) || defined(HAVE_MBTOWC))
# define PHP_HTTP_HAVE_WCHAR 1
#endif
#include
#define PHP_HTTP_IS_CTYPE(type, c) is##type((int) (unsigned char) (c))
#define PHP_HTTP_TO_CTYPE(type, c) to##type((int) (unsigned char) (c))
#include "php_http.h"
#include "php_http_buffer.h"
#include "php_http_misc.h"
#include "php_http_options.h"
#include "php_http.h"
#include "php_http_cookie.h"
#include "php_http_encoding.h"
#include "php_http_info.h"
#include "php_http_message.h"
#include "php_http_env.h"
#include "php_http_env_request.h"
#include "php_http_env_response.h"
#include "php_http_etag.h"
#include "php_http_exception.h"
#include "php_http_filter.h"
#include "php_http_header_parser.h"
#include "php_http_header.h"
#include "php_http_message_body.h"
#include "php_http_message_parser.h"
#include "php_http_negotiate.h"
#include "php_http_object.h"
#include "php_http_params.h"
#include "php_http_querystring.h"
#include "php_http_client.h"
#include "php_http_curl.h"
#include "php_http_client_request.h"
#include "php_http_client_response.h"
#include "php_http_client_curl.h"
#include "php_http_url.h"
#include "php_http_version.h"
ZEND_BEGIN_MODULE_GLOBALS(php_http)
struct php_http_env_globals env;
#ifdef PHP_HTTP_HAVE_CLIENT
struct {
#ifdef PHP_HTTP_HAVE_CURL
struct php_http_client_curl_globals curl;
#endif
} client;
#endif
ZEND_END_MODULE_GLOBALS(php_http)
ZEND_EXTERN_MODULE_GLOBALS(php_http);
#ifdef ZTS
# include "TSRM/TSRM.h"
# define PHP_HTTP_G ((zend_php_http_globals *) (*((void ***) tsrm_get_ls_cache()))[TSRM_UNSHUFFLE_RSRC_ID(php_http_globals_id)])
# undef TSRMLS_FETCH_FROM_CTX
# define TSRMLS_FETCH_FROM_CTX(ctx) ERROR
#else
# define PHP_HTTP_G (&php_http_globals)
#endif
#if PHP_DEBUG
# define _DPF_STR 0
# define _DPF_IN 1
# define _DPF_OUT 2
extern void _dpf(int type, const char *data, size_t length);
#else
# define _dpf(t,s,l);
#endif
#endif /* PHP_HTTP_API_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_buffer.c 0000644 0001750 0000144 00000027535 12667772426 016512 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include
#include "php_http_buffer.h"
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(
php_http_buffer_t *buf, size_t chunk_size, unsigned flags)
{
if (!buf) {
buf = pemalloc(sizeof(*buf), flags & PHP_HTTP_BUFFER_INIT_PERSISTENT);
}
if (buf) {
buf->size = (chunk_size) ? chunk_size : PHP_HTTP_BUFFER_DEFAULT_SIZE;
buf->pmem = (flags & PHP_HTTP_BUFFER_INIT_PERSISTENT) ? 1 : 0;
buf->data = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ?
pemalloc(buf->size, buf->pmem) : NULL;
buf->free = (flags & PHP_HTTP_BUFFER_INIT_PREALLOC) ? buf->size : 0;
buf->used = 0;
}
return buf;
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(
php_http_buffer_t *buf, const char *str, size_t len)
{
if ((buf = php_http_buffer_init(buf))) {
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(buf, str, len)) {
pefree(buf, buf->pmem);
buf = NULL;
}
}
return buf;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(
php_http_buffer_t *buf, size_t len, size_t override_size,
zend_bool allow_error)
{
char *ptr = NULL;
#if 0
fprintf(stderr, "RESIZE: len=%lu, size=%lu, used=%lu, free=%lu, total=%lu\n", len, buf->size, buf->used, buf->free, buf->free+buf->used);
#endif
if (buf->free < len) {
size_t size = override_size ? override_size : buf->size;
while ((size + buf->free) < len) {
size <<= 1;
}
if (allow_error) {
ptr = perealloc_recoverable(buf->data,
buf->used + buf->free + size, buf->pmem);
} else {
ptr = perealloc(buf->data, buf->used + buf->free + size, buf->pmem);
}
if (ptr) {
buf->data = ptr;
} else {
return PHP_HTTP_BUFFER_NOMEM;
}
buf->free += size;
return size;
}
return 0;
}
PHP_HTTP_BUFFER_API char *php_http_buffer_account(
php_http_buffer_t *buf, size_t to_account)
{
assert(to_account <= buf->free);
buf->free -= to_account;
buf->used += to_account;
return buf->data + buf->used;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf)
{
/* avoid another realloc on fixation */
if (buf->free > 1) {
char *ptr = perealloc(buf->data, buf->used + 1, buf->pmem);
if (ptr) {
buf->data = ptr;
} else {
return PHP_HTTP_BUFFER_NOMEM;
}
buf->free = 1;
}
return buf->used;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf,
const char *append, size_t append_len)
{
if ( buf->free < append_len &&
PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, append_len)
) {
return PHP_HTTP_BUFFER_NOMEM;
}
memcpy(buf->data + buf->used, append, append_len);
buf->used += append_len;
buf->free -= append_len;
return append_len;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf,
const char *format, ...)
{
va_list argv;
char *append;
size_t append_len, alloc;
va_start(argv, format);
append_len = vspprintf(&append, 0, format, argv);
va_end(argv);
alloc = php_http_buffer_append(buf, append, append_len);
efree(append);
if (PHP_HTTP_BUFFER_NOMEM == alloc) {
return PHP_HTTP_BUFFER_NOMEM;
}
return append_len;
}
PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf,
char **into, size_t *len)
{
char *copy = ecalloc(1, buf->used + 1);
memcpy(copy, buf->data, buf->used);
if (into) {
*into = copy;
}
if (len) {
*len = buf->used;
}
return copy;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf,
size_t offset, size_t length)
{
if (offset > buf->used) {
return 0;
}
if (offset + length > buf->used) {
length = buf->used - offset;
}
memmove(buf->data + offset, buf->data + offset + length,
buf->used - length - offset);
buf->used -= length;
buf->free += length;
return length;
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(
php_http_buffer_t *buf)
{
if ( buf->free < 1 &&
PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(buf, 1, 1, 0)
) {
return NULL;
}
buf->data[buf->used] = '\0';
return buf;
}
PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf)
{
buf->free += buf->used;
buf->used = 0;
}
PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf)
{
if (buf->data) {
pefree(buf->data, buf->pmem);
buf->data = NULL;
}
buf->used = 0;
buf->free = 0;
}
PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf)
{
if (*buf) {
php_http_buffer_dtor(*buf);
pefree(*buf, (*buf)->pmem);
*buf = NULL;
}
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s,
const char *data, size_t data_len, char **chunk, size_t chunk_size)
{
php_http_buffer_t *storage;
*chunk = NULL;
if (!*s) {
*s = php_http_buffer_init_ex(NULL, chunk_size << 1,
chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
}
storage = *s;
if (data_len) {
php_http_buffer_append(storage, data, data_len);
}
if (!chunk_size) {
php_http_buffer_data(storage, chunk, &chunk_size);
php_http_buffer_free(s);
return chunk_size;
}
if (storage->used >= chunk_size) {
*chunk = estrndup(storage->data, chunk_size);
php_http_buffer_cut(storage, 0, chunk_size);
return chunk_size;
}
return 0;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s,
const char *data, size_t data_len, size_t chunk_len,
php_http_buffer_pass_func_t passout, void *opaque)
{
char *chunk = NULL;
size_t passed = 0, got = 0;
while ((got = php_http_buffer_chunk_buffer(s, data, data_len, &chunk, chunk_len))) {
if (PHP_HTTP_BUFFER_PASS0 == passout(opaque, chunk, got)) {
PTR_SET(chunk, NULL);
return PHP_HTTP_BUFFER_PASS0;
}
++passed;
if (!chunk_len) {
/* we already got the last chunk,
and freed all resources */
break;
}
data = NULL;
data_len = 0;
PTR_SET(chunk, NULL);
}
PTR_FREE(chunk);
return passed;
}
PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size,
php_http_buffer_pass_func_t passin, void *passin_arg,
php_http_buffer_pass_func_t passon, void *passon_arg)
{
size_t passed_on = 0, passed_in;
passed_in = php_http_buffer_chunked_input(s, chunk_size, passin, passin_arg);
if (passed_in == PHP_HTTP_BUFFER_PASS0) {
return passed_in;
}
if (passed_in || (*s)->used) {
passed_on = passon(passon_arg, (*s)->data, (*s)->used);
if (passed_on == PHP_HTTP_BUFFER_PASS0) {
return passed_on;
}
if (passed_on) {
php_http_buffer_cut(*s, 0, passed_on);
}
}
return passed_on - passed_in;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s,
size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque)
{
php_http_buffer_t *str;
size_t passed;
if (!*s) {
*s = php_http_buffer_init_ex(NULL, chunk_size,
chunk_size ? PHP_HTTP_BUFFER_INIT_PREALLOC : 0);
}
str = *s;
php_http_buffer_resize(str, chunk_size);
passed = passin(opaque, str->data + str->used, chunk_size);
if (passed != PHP_HTTP_BUFFER_PASS0) {
str->used += passed;
str->free -= passed;
}
php_http_buffer_fix(str);
return passed;
}
#ifdef PHP_HTTP_BUFFER_EXTENDED
PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left,
php_http_buffer_t *right)
{
if (left->used > right->used) {
return -1;
} else if (right->used > left->used) {
return 1;
} else {
return memcmp(left->data, right->data, left->used);
}
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(
const php_http_buffer_t *from, php_http_buffer_t *to)
{
int free_to = !to;
to = php_http_buffer_clone(from, to);
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(to, from->data, from->used)) {
if (free_to) {
php_http_buffer_free(&to);
} else {
php_http_buffer_dtor(to);
}
}
return to;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *buf,
const char *insert, size_t insert_len, size_t offset)
{
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, insert_len)) {
return PHP_HTTP_BUFFER_NOMEM;
}
memmove(buf->data + offset + insert_len, buf->data + offset, insert_len);
memcpy(buf->data + offset, insert, insert_len);
buf->used += insert_len;
buf->free -= insert_len;
return insert_len;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf,
size_t offset, const char *format, ...)
{
va_list argv;
char *insert;
size_t insert_len, alloc;
va_start(argv, format);
insert_len = vspprintf(&insert, 0, format, argv);
va_end(argv);
alloc = php_http_buffer_insert(buf, insert, insert_len, offset);
efree(insert);
if (PHP_HTTP_BUFFER_NOMEM == alloc) {
return PHP_HTTP_BUFFER_NOMEM;
}
return insert_len;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf,
const char *prepend, size_t prepend_len)
{
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize(buf, prepend_len)) {
return PHP_HTTP_BUFFER_NOMEM;
}
memmove(buf->data + prepend_len, buf->data, buf->used);
memcpy(buf->data, prepend, prepend_len);
buf->used += prepend_len;
buf->free -= prepend_len;
return prepend_len;
}
PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf,
const char *format, ...)
{
va_list argv;
char *prepend;
size_t prepend_len, alloc;
va_start(argv, format);
prepend_len = vspprintf(&prepend, 0, format, argv);
va_end(argv);
alloc = php_http_buffer_prepend(buf, prepend, prepend_len);
efree(prepend);
if (PHP_HTTP_BUFFER_NOMEM == alloc) {
return PHP_HTTP_BUFFER_NOMEM;
}
return prepend_len;
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(
const php_http_buffer_t *buf, size_t offset, size_t length)
{
if (offset >= buf->used) {
return NULL;
} else {
php_http_buffer_t *sub;
size_t need = 1 + ((length + offset) > buf->used ?
(buf->used - offset) : (length - offset));
unsigned flags = buf->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0;
sub = php_http_buffer_init_ex(NULL, need,
PHP_HTTP_BUFFER_INIT_PREALLOC | flags);
if (sub) {
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(sub, buf->data + offset, need)) {
php_http_buffer_free(&sub);
} else {
sub->size = buf->size;
}
}
return sub;
}
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(
const php_http_buffer_t *buf, size_t length)
{
if (length < buf->used) {
return php_http_buffer_sub(buf, buf->used - length, length);
} else {
return php_http_buffer_sub(buf, 0, buf->used);
}
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(
php_http_buffer_t *buf, unsigned argc, va_list argv)
{
unsigned i = 0;
buf = php_http_buffer_init(buf);
if (buf) {
while (argc > i++) {
php_http_buffer_free_t f = va_arg(argv, php_http_buffer_free_t);
php_http_buffer_t *current = va_arg(argv, php_http_buffer_t *);
php_http_buffer_append(buf, current->data, current->used);
FREE_PHP_HTTP_BUFFER(f, current);
}
}
return buf;
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(
php_http_buffer_t *buf, unsigned argc, ...)
{
va_list argv;
php_http_buffer_t *ret;
va_start(argv, argc);
ret = php_http_buffer_merge_va(buf, argc, argv);
va_end(argv);
return ret;
}
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...)
{
va_list argv;
php_http_buffer_t *ret;
va_start(argv, argc);
ret = php_http_buffer_merge_va(NULL, argc, argv);
va_end(argv);
return ret;
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_buffer.h 0000644 0001750 0000144 00000024407 12667772426 016512 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_BUFFER_H
#define PHP_HTTP_BUFFER_H
#ifndef PHP_HTTP_BUFFER_DEFAULT_SIZE
# define PHP_HTTP_BUFFER_DEFAULT_SIZE 256
#endif
#define PHP_HTTP_BUFFER_ERROR ((size_t) -1)
#define PHP_HTTP_BUFFER_NOMEM PHP_HTTP_BUFFER_ERROR
#define PHP_HTTP_BUFFER_PASS0 PHP_HTTP_BUFFER_ERROR
#ifndef PTR_FREE
# define PTR_FREE(PTR) \
{ \
if (PTR) { \
efree(PTR); \
} \
}
#endif
#ifndef PTR_SET
# define PTR_SET(PTR, SET) \
{ \
PTR_FREE(PTR); \
PTR = SET; \
}
#endif
#ifdef PHP_ATTRIBUTE_FORMAT
# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b) PHP_ATTRIBUTE_FORMAT(f, a, b)
#else
# define PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(f, a, b)
#endif
#ifndef pemalloc
# define pemalloc(s,p) malloc(s)
# define pefree(x,p) free(x)
# define perealloc(x,s,p) realloc(x,s)
# define perealloc_recoverable perealloc
# define ecalloc calloc
static inline void *estrndup(void *p, size_t s)
{
char *r = (char *) malloc(s+1);
if (r) memcpy((void *) r, p, s), r[s] = '\0';
return (void *) r;
}
#endif
#if defined(PHP_WIN32)
# if defined(PHP_HTTP_BUFFER_EXPORTS)
# define PHP_HTTP_BUFFER_API __declspec(dllexport)
# elif defined(COMPILE_DL_PHP_HTTP_BUFFER)
# define PHP_HTTP_BUFFER_API __declspec(dllimport)
# else
# define PHP_HTTP_BUFFER_API
# endif
#else
# define PHP_HTTP_BUFFER_API
#endif
#define PHP_HTTP_BUFFER(p) ((php_http_buffer_t *) (p))
#define FREE_PHP_HTTP_BUFFER_PTR(STR) pefree(STR, STR->pmem)
#define FREE_PHP_HTTP_BUFFER_VAL(STR) php_http_buffer_dtor(STR)
#define FREE_PHP_HTTP_BUFFER_ALL(STR) php_http_buffer_free(&(STR))
#define FREE_PHP_HTTP_BUFFER(free, STR) \
switch (free) \
{ \
case PHP_HTTP_BUFFER_FREE_NOT: \
break; \
case PHP_HTTP_BUFFER_FREE_PTR: \
pefree(STR, STR->pmem); \
break; \
case PHP_HTTP_BUFFER_FREE_VAL: \
php_http_buffer_dtor(STR); \
break; \
case PHP_HTTP_BUFFER_FREE_ALL: { \
php_http_buffer_t *PTR = (STR); \
php_http_buffer_free(&PTR); \
break; \
} \
default:\
break; \
}
#define RETURN_PHP_HTTP_BUFFER_PTR(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0)
#define RETURN_PHP_HTTP_BUFFER_VAL(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0)
#define RETURN_PHP_HTTP_BUFFER_DUP(STR) RETURN_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1)
#define RETVAL_PHP_HTTP_BUFFER_PTR(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_PTR, 0)
#define RETVAL_PHP_HTTP_BUFFER_VAL(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 0)
#define RETVAL_PHP_HTTP_BUFFER_DUP(STR) RETVAL_PHP_HTTP_BUFFER((STR), PHP_HTTP_BUFFER_FREE_NOT, 1)
/* RETURN_PHP_HTTP_BUFFER(buf, PHP_HTTP_BUFFER_FREE_PTR, 0) */
#define RETURN_PHP_HTTP_BUFFER(STR, free, dup) \
RETVAL_PHP_HTTP_BUFFER((STR), (free), (dup)); \
return;
#define RETVAL_PHP_HTTP_BUFFER(STR, free, dup) \
php_http_buffer_fix(STR); \
RETVAL_STRINGL((STR)->data, (STR)->used, (dup)); \
FREE_PHP_HTTP_BUFFER((free), (STR));
typedef struct php_http_buffer {
char *data;
size_t used;
size_t free;
size_t size;
unsigned pmem:1;
unsigned reserved:31;
} php_http_buffer_t;
typedef enum php_http_buffer_free {
PHP_HTTP_BUFFER_FREE_NOT = 0,
PHP_HTTP_BUFFER_FREE_PTR, /* pefree() */
PHP_HTTP_BUFFER_FREE_VAL, /* php_http_buffer_dtor() */
PHP_HTTP_BUFFER_FREE_ALL /* php_http_buffer_free() */
} php_http_buffer_free_t;
#define PHP_HTTP_BUFFER_ALL_FREE(STR) PHP_HTTP_BUFFER_FREE_ALL,(STR)
#define PHP_HTTP_BUFFER_PTR_FREE(STR) PHP_HTTP_BUFFER_FREE_PTR,(STR)
#define PHP_HTTP_BUFFER_VAL_FREE(STR) PHP_HTTP_BUFFER_FREE_VAL,(STR)
#define PHP_HTTP_BUFFER_NOT_FREE(STR) PHP_HTTP_BUFFER_FREE_NOT,(STR)
#define PHP_HTTP_BUFFER_INIT_PREALLOC 0x01
#define PHP_HTTP_BUFFER_INIT_PERSISTENT 0x02
/* create a new php_http_buffer_t */
#define php_http_buffer_new() php_http_buffer_init(NULL)
#define php_http_buffer_init(b) php_http_buffer_init_ex(b, PHP_HTTP_BUFFER_DEFAULT_SIZE, 0)
#define php_http_buffer_clone(from, to) php_http_buffer_init_ex((to), (from)->size, (from)->pmem ? PHP_HTTP_BUFFER_INIT_PERSISTENT:0)
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_init_ex(php_http_buffer_t *buf, size_t chunk_size, unsigned flags);
/* create a php_http_buffer_t from a zval or c-string */
#define php_http_buffer_from_zval(z) php_http_buffer_from_string(Z_STRVAL(z), Z_STRLEN(z))
#define php_http_buffer_from_zval_ex(b, z) php_http_buffer_from_string_ex(b, Z_STRVAL(z), Z_STRLEN(z))
#define php_http_buffer_from_string(s, l) php_http_buffer_from_string_ex(NULL, (s), (l))
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_from_string_ex(php_http_buffer_t *buf, const char *string, size_t length);
/* usually only called from within the internal functions */
#define php_http_buffer_resize(b, s) php_http_buffer_resize_ex((b), (s), 0, 0)
PHP_HTTP_BUFFER_API size_t php_http_buffer_resize_ex(php_http_buffer_t *buf, size_t len, size_t override_size, zend_bool allow_error);
PHP_HTTP_BUFFER_API char *php_http_buffer_account(php_http_buffer_t *buf, size_t to_account);
/* shrink memory chunk to actually used size (+1) */
PHP_HTTP_BUFFER_API size_t php_http_buffer_shrink(php_http_buffer_t *buf);
/* append data to the php_http_buffer_t */
#define php_http_buffer_appends(b, a) php_http_buffer_append((b), (a), sizeof(a)-1)
#define php_http_buffer_appendl(b, a) php_http_buffer_append((b), (a), strlen(a))
#define php_http_buffer_appendz(b, z) php_http_buffer_append((b), (z)->val, (z)->len)
PHP_HTTP_BUFFER_API size_t php_http_buffer_append(php_http_buffer_t *buf, const char *append, size_t append_len);
PHP_HTTP_BUFFER_API size_t php_http_buffer_appendf(php_http_buffer_t *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3);
/* get a zero-terminated string */
PHP_HTTP_BUFFER_API char *php_http_buffer_data(const php_http_buffer_t *buf, char **into, size_t *len);
/* remove a substring */
PHP_HTTP_BUFFER_API size_t php_http_buffer_cut(php_http_buffer_t *buf, size_t offset, size_t length);
/* sets a trailing NUL byte */
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_fix(php_http_buffer_t *buf);
/* reset php_http_buffer_t object */
PHP_HTTP_BUFFER_API void php_http_buffer_reset(php_http_buffer_t *buf);
/* free a php_http_buffer_t objects contents */
PHP_HTTP_BUFFER_API void php_http_buffer_dtor(php_http_buffer_t *buf);
/* free a php_http_buffer_t object completely */
PHP_HTTP_BUFFER_API void php_http_buffer_free(php_http_buffer_t **buf);
/* stores data in a php_http_buffer_t until it reaches chunk_size */
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunk_buffer(php_http_buffer_t **s, const char *data, size_t data_len, char **chunk, size_t chunk_size);
typedef size_t (*php_http_buffer_pass_func_t)(void *opaque, char *, size_t);
PHP_HTTP_BUFFER_API ssize_t php_http_buffer_passthru(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *passin_arg, php_http_buffer_pass_func_t passon, void *passon_arg);
/* wrapper around php_http_buffer_chunk_buffer, which passes available chunks to passthru() */
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_output(php_http_buffer_t **s, const char *data, size_t data_len, size_t chunk_size, php_http_buffer_pass_func_t passout, void *opaque);
/* write chunks directly into php_http_buffer_t buffer */
PHP_HTTP_BUFFER_API size_t php_http_buffer_chunked_input(php_http_buffer_t **s, size_t chunk_size, php_http_buffer_pass_func_t passin, void *opaque);
# ifdef PHP_HTTP_BUFFER_EXTENDED
/* memcmp for php_http_buffer_t objects */
PHP_HTTP_BUFFER_API int php_http_buffer_cmp(php_http_buffer_t *left, php_http_buffer_t *right);
/* get a complete php_http_buffer_t duplicate */
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_copy(const php_http_buffer_t *from, php_http_buffer_t *to);
/* merge several php_http_buffer_t objects
use like:
php_http_buffer_t *final = php_http_buffer_merge(3,
PHP_HTTP_BUFFER_NOT_FREE(&keep),
PHP_HTTP_BUFFER_ALL_FREE(middle_ptr),
PHP_HTTP_BUFFER_VAL_FREE(&local);
*/
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge(unsigned argc, ...);
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_ex(php_http_buffer_t *buf, unsigned argc, ...);
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_merge_va(php_http_buffer_t *buf, unsigned argc, va_list argv);
/* insert data at a specific position of the php_http_buffer_t */
#define php_http_buffer_inserts(b, i, o) php_http_buffer_insert((b), (i), sizeof(i)-1, (o))
#define php_http_buffer_insertl(b, i, o) php_http_buffer_insert((b), (i), strlen(i), (o))
PHP_HTTP_BUFFER_API size_t php_http_buffer_insert(php_http_buffer_t *buf, const char *insert, size_t insert_len, size_t offset);
PHP_HTTP_BUFFER_API size_t php_http_buffer_insertf(php_http_buffer_t *buf, size_t offset, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 3, 4);
/* prepend data */
#define php_http_buffer_prepends(b, p) php_http_buffer_prepend((b), (p), sizeof(p)-1)
#define php_http_buffer_prependl(b, p) php_http_buffer_prepend((b), (p), strlen(p))
PHP_HTTP_BUFFER_API size_t php_http_buffer_prepend(php_http_buffer_t *buf, const char *prepend, size_t prepend_len);
PHP_HTTP_BUFFER_API size_t php_http_buffer_prependf(php_http_buffer_t *buf, const char *format, ...) PHP_HTTP_BUFFER_ATTRIBUTE_FORMAT(printf, 2, 3);
/* get a part of the php_http_buffer_t */
#define php_http_buffer_mid(b, o, l) php_http_buffer_sub((b), (o), (l))
#define php_http_buffer_left(b, l) php_http_buffer_sub((b), 0, (l))
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_right(const php_http_buffer_t *buf, size_t length);
PHP_HTTP_BUFFER_API php_http_buffer_t *php_http_buffer_sub(const php_http_buffer_t *buf, size_t offset, size_t len);
# endif /* PHP_HTTP_BUFFER_EXTENDED */
#endif /* PHP_HTTP_BUFFER_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http.c 0000644 0001750 0000144 00000013527 12667772426 015155 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
#include
#include
#if PHP_HTTP_HAVE_CURL
# include
# if PHP_HTTP_HAVE_EVENT
# if PHP_HTTP_HAVE_EVENT2
# include
# include
# else
# include
# endif
# endif
#endif
#if PHP_HTTP_HAVE_IDN2
# include
#elif PHP_HTTP_HAVE_IDN
# include
#endif
ZEND_DECLARE_MODULE_GLOBALS(php_http);
#ifdef COMPILE_DL_HTTP
ZEND_GET_MODULE(http)
#endif
zend_function_entry http_functions[] = {
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http);
PHP_MSHUTDOWN_FUNCTION(http);
PHP_RSHUTDOWN_FUNCTION(http);
PHP_MINFO_FUNCTION(http);
static zend_module_dep http_module_deps[] = {
ZEND_MOD_REQUIRED("raphf")
ZEND_MOD_REQUIRED("propro")
ZEND_MOD_REQUIRED("spl")
#ifdef PHP_HTTP_HAVE_HASH
ZEND_MOD_REQUIRED("hash")
#endif
#ifdef PHP_HTTP_HAVE_ICONV
ZEND_MOD_REQUIRED("iconv")
#endif
{NULL, NULL, NULL, 0}
};
zend_module_entry http_module_entry = {
STANDARD_MODULE_HEADER_EX,
NULL,
http_module_deps,
"http",
http_functions,
PHP_MINIT(http),
PHP_MSHUTDOWN(http),
NULL,
PHP_RSHUTDOWN(http),
PHP_MINFO(http),
PHP_PECL_HTTP_VERSION,
STANDARD_MODULE_PROPERTIES
};
int http_module_number;
#if PHP_DEBUG && !HAVE_GCOV
void _dpf(int type, const char *data, size_t length)
{
static const char _sym[] = "><><><";
if (type) {
int nwp = 0;
for (fprintf(stderr, "%c ", _sym[type-1]); length--; data++) {
int ip = PHP_HTTP_IS_CTYPE(print, *data);
if (!ip && *data != '\r' && *data != '\n') nwp = 1;
fprintf(stderr, ip?"%c":"\\x%02x", (int) (*data & 0xff));
if (!nwp && *data == '\n' && length) {
fprintf(stderr, "\n%c ", _sym[type-1]);
}
}
fprintf(stderr, "\n");
} else {
fprintf(stderr, "# %.*s\n", (int) length, data);
}
}
#endif
static void php_http_globals_init_once(zend_php_http_globals *G)
{
memset(G, 0, sizeof(*G));
}
#if 0
static inline void php_http_globals_init(zend_php_http_globals *G)
{
}
static inline void php_http_globals_free(zend_php_http_globals *G)
{
}
#endif
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode, zend_php_http_globals, php_http_globals)
PHP_INI_END()
PHP_MINIT_FUNCTION(http)
{
http_module_number = module_number;
ZEND_INIT_MODULE_GLOBALS(php_http, php_http_globals_init_once, NULL);
REGISTER_INI_ENTRIES();
if (0
|| SUCCESS != PHP_MINIT_CALL(http_object)
|| SUCCESS != PHP_MINIT_CALL(http_exception)
|| SUCCESS != PHP_MINIT_CALL(http_cookie)
|| SUCCESS != PHP_MINIT_CALL(http_encoding)
|| SUCCESS != PHP_MINIT_CALL(http_filter)
|| SUCCESS != PHP_MINIT_CALL(http_header)
|| SUCCESS != PHP_MINIT_CALL(http_header_parser)
|| SUCCESS != PHP_MINIT_CALL(http_message)
|| SUCCESS != PHP_MINIT_CALL(http_message_parser)
|| SUCCESS != PHP_MINIT_CALL(http_message_body)
|| SUCCESS != PHP_MINIT_CALL(http_querystring)
|| SUCCESS != PHP_MINIT_CALL(http_client)
|| SUCCESS != PHP_MINIT_CALL(http_client_request)
|| SUCCESS != PHP_MINIT_CALL(http_client_response)
#if PHP_HTTP_HAVE_CURL
|| SUCCESS != PHP_MINIT_CALL(http_curl)
|| SUCCESS != PHP_MINIT_CALL(http_client_curl)
#endif
|| SUCCESS != PHP_MINIT_CALL(http_url)
|| SUCCESS != PHP_MINIT_CALL(http_env)
|| SUCCESS != PHP_MINIT_CALL(http_env_request)
|| SUCCESS != PHP_MINIT_CALL(http_env_response)
|| SUCCESS != PHP_MINIT_CALL(http_params)
) {
return FAILURE;
}
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(http)
{
UNREGISTER_INI_ENTRIES();
if (0
|| SUCCESS != PHP_MSHUTDOWN_CALL(http_message)
#if PHP_HTTP_HAVE_CURL
|| SUCCESS != PHP_MSHUTDOWN_CALL(http_client_curl)
|| SUCCESS != PHP_MSHUTDOWN_CALL(http_curl)
#endif
|| SUCCESS != PHP_MSHUTDOWN_CALL(http_client)
) {
return FAILURE;
}
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(http)
{
if (0
|| SUCCESS != PHP_RSHUTDOWN_CALL(http_env)
) {
return FAILURE;
}
return SUCCESS;
}
PHP_MINFO_FUNCTION(http)
{
php_http_buffer_t buf;
php_http_buffer_init(&buf);
php_info_print_table_start();
php_info_print_table_header(2, "HTTP Support", "enabled");
php_info_print_table_row(2, "Extension Version", PHP_PECL_HTTP_VERSION);
php_info_print_table_end();
php_info_print_table_start();
php_info_print_table_header(3, "Used Library", "Compiled", "Linked");
php_info_print_table_row(3, "libz", ZLIB_VERSION, zlibVersion());
#if PHP_HTTP_HAVE_CURL
{
curl_version_info_data *cv = curl_version_info(CURLVERSION_NOW);
php_info_print_table_row(3, "libcurl", LIBCURL_VERSION, cv->version);
}
#else
php_info_print_table_row(3, "libcurl", "disabled", "disabled");
#endif
#if PHP_HTTP_HAVE_EVENT
php_info_print_table_row(3, "libevent",
# ifdef LIBEVENT_VERSION
LIBEVENT_VERSION,
# else
PHP_HTTP_EVENT_VERSION,
# endif
event_get_version());
#else
php_info_print_table_row(3, "libevent", "disabled", "disabled");
#endif
#if PHP_HTTP_HAVE_IDN2
php_info_print_table_row(3, "libidn2 (IDNA2008)", IDN2_VERSION, idn2_check_version(NULL));
#elif PHP_HTTP_HAVE_IDN
php_info_print_table_row(3, "libidn (IDNA2003)", PHP_HTTP_LIBIDN_VERSION, "unknown");
#endif
php_info_print_table_end();
DISPLAY_INI_ENTRIES();
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client.c 0000644 0001750 0000144 00000116654 12667772426 016520 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include "php_http_client.h"
#include
/*
* array of name => php_http_client_driver_t*
*/
static HashTable php_http_client_drivers;
static void php_http_client_driver_hash_dtor(zval *pData)
{
pefree(Z_PTR_P(pData), 1);
}
ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver)
{
return zend_hash_add_mem(&php_http_client_drivers, driver->driver_name, (void *) driver, sizeof(php_http_client_driver_t))
? SUCCESS : FAILURE;
}
php_http_client_driver_t *php_http_client_driver_get(zend_string *name)
{
zval *ztmp;
php_http_client_driver_t *tmp;
if (name && (tmp = zend_hash_find_ptr(&php_http_client_drivers, name))) {
return tmp;
}
if ((ztmp = zend_hash_get_current_data(&php_http_client_drivers))) {
return Z_PTR_P(ztmp);
}
return NULL;
}
static int apply_driver_list(zval *p, void *arg)
{
php_http_client_driver_t *d = Z_PTR_P(p);
zval zname;
ZVAL_STR_COPY(&zname, d->driver_name);
zend_hash_next_index_insert(arg, &zname);
return ZEND_HASH_APPLY_KEEP;
}
void php_http_client_driver_list(HashTable *ht)
{
zend_hash_apply_with_argument(&php_http_client_drivers, apply_driver_list, ht);
}
static zend_class_entry *php_http_client_class_entry;
zend_class_entry *php_http_client_get_class_entry(void)
{
return php_http_client_class_entry;
}
void php_http_client_options_set_subr(zval *instance, char *key, size_t len, zval *opts, int overwrite)
{
if (overwrite || (opts && zend_hash_num_elements(Z_ARRVAL_P(opts)))) {
zend_class_entry *this_ce = Z_OBJCE_P(instance);
zval old_opts_tmp, *old_opts, new_opts, *entry = NULL;
array_init(&new_opts);
old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
if (Z_TYPE_P(old_opts) == IS_ARRAY) {
array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
}
if (overwrite) {
if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
Z_ADDREF_P(opts);
zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
} else {
zend_symtable_str_del(Z_ARRVAL(new_opts), key, len);
}
} else if (opts && zend_hash_num_elements(Z_ARRVAL_P(opts))) {
if ((entry = zend_symtable_str_find(Z_ARRVAL(new_opts), key, len))) {
array_join(Z_ARRVAL_P(opts), Z_ARRVAL_P(entry), 0, 0);
} else {
Z_ADDREF_P(opts);
zend_symtable_str_update(Z_ARRVAL(new_opts), key, len, opts);
}
}
zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
zval_ptr_dtor(&new_opts);
}
}
void php_http_client_options_set(zval *instance, zval *opts)
{
php_http_arrkey_t key;
zval new_opts;
zend_class_entry *this_ce = Z_OBJCE_P(instance);
zend_bool is_client = instanceof_function(this_ce, php_http_client_class_entry);
array_init(&new_opts);
if (!opts || !zend_hash_num_elements(Z_ARRVAL_P(opts))) {
zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
zval_ptr_dtor(&new_opts);
} else {
zval old_opts_tmp, *old_opts, add_opts, *opt;
array_init(&add_opts);
/* some options need extra attention -- thus cannot use array_merge() directly */
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(opts), key.h, key.key, opt)
{
if (key.key) {
if (Z_TYPE_P(opt) == IS_ARRAY && (zend_string_equals_literal(key.key, "ssl") || zend_string_equals_literal(key.key, "cookies"))) {
php_http_client_options_set_subr(instance, key.key->val, key.key->len, opt, 0);
} else if (is_client && (zend_string_equals_literal(key.key, "recordHistory") || zend_string_equals_literal(key.key, "responseMessageClass"))) {
zend_update_property(this_ce, instance, key.key->val, key.key->len, opt);
} else if (Z_TYPE_P(opt) == IS_NULL) {
old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
if (Z_TYPE_P(old_opts) == IS_ARRAY) {
zend_symtable_del(Z_ARRVAL_P(old_opts), key.key);
}
} else {
Z_TRY_ADDREF_P(opt);
add_assoc_zval_ex(&add_opts, key.key->val, key.key->len, opt);
}
}
}
ZEND_HASH_FOREACH_END();
old_opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &old_opts_tmp);
if (Z_TYPE_P(old_opts) == IS_ARRAY) {
array_copy(Z_ARRVAL_P(old_opts), Z_ARRVAL(new_opts));
}
array_join(Z_ARRVAL(add_opts), Z_ARRVAL(new_opts), 0, 0);
zend_update_property(this_ce, instance, ZEND_STRL("options"), &new_opts);
zval_ptr_dtor(&new_opts);
zval_ptr_dtor(&add_opts);
}
}
void php_http_client_options_get_subr(zval *instance, char *key, size_t len, zval *return_value)
{
zend_class_entry *this_ce = Z_OBJCE_P(instance);
zval *options, opts_tmp, *opts = zend_read_property(this_ce, instance, ZEND_STRL("options"), 0, &opts_tmp);
if ((Z_TYPE_P(opts) == IS_ARRAY) && (options = zend_symtable_str_find(Z_ARRVAL_P(opts), key, len))) {
RETVAL_ZVAL(options, 1, 0);
}
}
static void queue_dtor(void *enqueued)
{
php_http_client_enqueue_t *e = enqueued;
if (e->dtor) {
e->dtor(e);
}
}
php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg)
{
php_http_client_t *free_h = NULL;
if (!h) {
free_h = h = emalloc(sizeof(*h));
}
memset(h, 0, sizeof(*h));
h->ops = ops;
if (rf) {
h->rf = rf;
} else if (ops->rsrc) {
h->rf = php_resource_factory_init(NULL, h->ops->rsrc, h, NULL);
}
zend_llist_init(&h->requests, sizeof(php_http_client_enqueue_t), queue_dtor, 0);
zend_llist_init(&h->responses, sizeof(void *), NULL, 0);
if (h->ops->init) {
if (!(h = h->ops->init(h, init_arg))) {
php_error_docref(NULL, E_WARNING, "Could not initialize client");
PTR_FREE(free_h);
}
}
return h;
}
php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to)
{
if (from->ops->copy) {
return from->ops->copy(from, to);
}
return NULL;
}
void php_http_client_dtor(php_http_client_t *h)
{
php_http_client_reset(h);
if (h->ops->dtor) {
h->ops->dtor(h);
}
php_resource_factory_free(&h->rf);
}
void php_http_client_free(php_http_client_t **h) {
if (*h) {
php_http_client_dtor(*h);
efree(*h);
*h = NULL;
}
}
ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
{
if (h->ops->enqueue) {
if (php_http_client_enqueued(h, enqueue->request, NULL)) {
php_error_docref(NULL, E_WARNING, "Failed to enqueue request; request already in queue");
return FAILURE;
}
return h->ops->enqueue(h, enqueue);
}
return FAILURE;
}
ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request)
{
if (h->ops->dequeue) {
php_http_client_enqueue_t *enqueue = php_http_client_enqueued(h, request, NULL);
if (!enqueue) {
php_error_docref(NULL, E_WARNING, "Failed to dequeue request; request not in queue");
return FAILURE;
}
return h->ops->dequeue(h, enqueue);
}
return FAILURE;
}
php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func)
{
zend_llist_element *el = NULL;
if (compare_func) {
for (el = h->requests.head; el; el = el->next) {
if (compare_func((php_http_client_enqueue_t *) el->data, compare_arg)) {
break;
}
}
} else {
for (el = h->requests.head; el; el = el->next) {
if (((php_http_client_enqueue_t *) el->data)->request == compare_arg) {
break;
}
}
}
return el ? (php_http_client_enqueue_t *) el->data : NULL;
}
ZEND_RESULT_CODE php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout)
{
if (h->ops->wait) {
return h->ops->wait(h, custom_timeout);
}
return FAILURE;
}
int php_http_client_once(php_http_client_t *h)
{
if (h->ops->once) {
return h->ops->once(h);
}
return FAILURE;
}
ZEND_RESULT_CODE php_http_client_exec(php_http_client_t *h)
{
if (h->ops->exec) {
return h->ops->exec(h);
}
return FAILURE;
}
void php_http_client_reset(php_http_client_t *h)
{
if (h->ops->reset) {
h->ops->reset(h);
}
zend_llist_clean(&h->requests);
zend_llist_clean(&h->responses);
}
ZEND_RESULT_CODE php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
{
if (h->ops->setopt) {
return h->ops->setopt(h, opt, arg);
}
return FAILURE;
}
ZEND_RESULT_CODE php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr)
{
if (h->ops->getopt) {
return h->ops->getopt(h, opt, arg, res_ptr);
}
return FAILURE;
}
static zend_object_handlers php_http_client_object_handlers;
void php_http_client_object_free(zend_object *object)
{
php_http_client_object_t *o = PHP_HTTP_OBJ(object, NULL);
php_http_client_free(&o->client);
php_http_object_method_dtor(&o->notify);
php_http_object_method_free(&o->update);
zend_object_std_dtor(object);
}
php_http_client_object_t *php_http_client_object_new_ex(zend_class_entry *ce, php_http_client_t *client)
{
php_http_client_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
o->client = client;
o->zo.handlers = &php_http_client_object_handlers;
return o;
}
zend_object *php_http_client_object_new(zend_class_entry *ce)
{
return &php_http_client_object_new_ex(ce, NULL)->zo;
}
static void handle_history(zval *zclient, php_http_message_t *request, php_http_message_t *response)
{
zval new_hist, old_hist_tmp, *old_hist = zend_read_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), 0, &old_hist_tmp);
php_http_message_t *req_copy = php_http_message_copy(request, NULL);
php_http_message_t *res_copy = php_http_message_copy(response, NULL);
php_http_message_t *zipped = php_http_message_zip(res_copy, req_copy);
php_http_message_object_t *obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), zipped);
ZVAL_OBJ(&new_hist, &obj->zo);
if (Z_TYPE_P(old_hist) == IS_OBJECT) {
php_http_message_object_prepend(&new_hist, old_hist, 1);
}
zend_update_property(php_http_client_class_entry, zclient, ZEND_STRL("history"), &new_hist);
zval_ptr_dtor(&new_hist);
}
static ZEND_RESULT_CODE handle_response(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_message_t **response)
{
zend_bool dequeue = 0;
zval zclient;
php_http_message_t *msg;
php_http_client_progress_state_t *progress;
ZVAL_OBJ(&zclient, &((php_http_client_object_t*) arg)->zo);
if ((msg = *response)) {
php_http_message_object_t *msg_obj;
zval info, zresponse, zrequest, rec_hist_tmp;
HashTable *info_ht;
/* ensure the message is of type response (could be uninitialized in case of early error, like DNS) */
php_http_message_set_type(msg, PHP_HTTP_RESPONSE);
if (zend_is_true(zend_read_property(php_http_client_class_entry, &zclient, ZEND_STRL("recordHistory"), 0, &rec_hist_tmp))) {
handle_history(&zclient, e->request, *response);
}
/* hard detach, redirects etc. are in the history */
php_http_message_free(&msg->parent);
*response = NULL;
msg_obj = php_http_message_object_new_ex(php_http_get_client_response_class_entry(), msg);
ZVAL_OBJ(&zresponse, &msg_obj->zo);
ZVAL_OBJECT(&zrequest, &((php_http_message_object_t *) e->opaque)->zo, 1);
php_http_message_object_prepend(&zresponse, &zrequest, 1);
object_init(&info);
info_ht = HASH_OF(&info);
php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, e->request, &info_ht);
zend_update_property(php_http_get_client_response_class_entry(), &zresponse, ZEND_STRL("transferInfo"), &info);
zval_ptr_dtor(&info);
Z_ADDREF(zresponse);
zend_llist_add_element(&client->responses, &msg_obj);
if (e->closure.fci.size) {
zval retval;
zend_error_handling zeh;
ZVAL_UNDEF(&retval);
zend_fcall_info_argn(&e->closure.fci, 1, &zresponse);
zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
zend_fcall_info_call(&e->closure.fci, &e->closure.fcc, &retval, NULL);
zend_restore_error_handling(&zeh);
zend_fcall_info_argn(&e->closure.fci, 0);
if (Z_TYPE(retval) == IS_TRUE) {
dequeue = 1;
}
zval_ptr_dtor(&retval);
}
zval_ptr_dtor(&zresponse);
zval_ptr_dtor(&zrequest);
}
if (SUCCESS == php_http_client_getopt(client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, e->request, &progress)) {
progress->info = "finished";
progress->finished = 1;
client->callback.progress.func(client->callback.progress.arg, client, e, progress);
}
if (dequeue) {
php_http_client_dequeue(client, e->request);
}
return SUCCESS;
}
static void handle_progress(void *arg, php_http_client_t *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *progress)
{
zval zclient, args[2];
php_http_client_object_t *client_obj = arg;
zend_error_handling zeh;
ZVAL_OBJECT(&zclient, &client_obj->zo, 1);
ZVAL_OBJECT(&args[0], &((php_http_message_object_t *) e->opaque)->zo, 1);
object_init(&args[1]);
add_property_bool(&args[1], "started", progress->started);
add_property_bool(&args[1], "finished", progress->finished);
add_property_string(&args[1], "info", STR_PTR(progress->info));
add_property_double(&args[1], "dltotal", progress->dl.total);
add_property_double(&args[1], "dlnow", progress->dl.now);
add_property_double(&args[1], "ultotal", progress->ul.total);
add_property_double(&args[1], "ulnow", progress->ul.now);
zend_replace_error_handling(EH_NORMAL, NULL, &zeh);
php_http_object_method_call(&client_obj->notify, &zclient, NULL, 2, args);
zend_restore_error_handling(&zeh);
zval_ptr_dtor(&zclient);
zval_ptr_dtor(&args[0]);
zval_ptr_dtor(&args[1]);
}
static void response_dtor(void *data)
{
php_http_message_object_t *msg_obj = *(php_http_message_object_t **) data;
zend_objects_store_del(&msg_obj->zo);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_construct, 0, 0, 0)
ZEND_ARG_INFO(0, driver)
ZEND_ARG_INFO(0, persistent_handle_id)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, __construct)
{
zend_string *driver_name = NULL, *persistent_handle_name = NULL;
php_http_client_driver_t *driver;
php_resource_factory_t *rf = NULL;
php_http_client_object_t *obj;
zval os;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!S!", &driver_name, &persistent_handle_name), invalid_arg, return);
if (!zend_hash_num_elements(&php_http_client_drivers)) {
php_http_throw(unexpected_val, "No http\\Client drivers available", NULL);
return;
}
if (!(driver = php_http_client_driver_get(driver_name))) {
php_http_throw(unexpected_val, "Failed to locate \"%s\" client request handler", driver_name ? driver_name->val : "default");
return;
}
object_init_ex(&os, spl_ce_SplObjectStorage);
zend_update_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), &os);
zval_ptr_dtor(&os);
if (persistent_handle_name) {
php_persistent_handle_factory_t *pf;
if ((pf = php_persistent_handle_concede(NULL, driver->client_name, persistent_handle_name, NULL, NULL))) {
rf = php_persistent_handle_resource_factory_init(NULL, pf);
}
}
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(obj->client = php_http_client_init(NULL, driver->client_ops, rf, NULL), runtime, return);
php_http_object_method_init(&obj->notify, getThis(), ZEND_STRL("notify"));
obj->client->callback.response.func = handle_response;
obj->client->callback.response.arg = obj;
obj->client->callback.progress.func = handle_progress;
obj->client->callback.progress.arg = obj;
obj->client->responses.dtor = response_dtor;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_reset, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, reset)
{
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
obj->iterator = 0;
php_http_client_reset(obj->client);
RETVAL_ZVAL(getThis(), 1, 0);
}
static HashTable *combined_options(zval *client, zval *request)
{
HashTable *options;
unsigned num_options = 0;
zval z_roptions, z_options_tmp, *z_coptions = zend_read_property(php_http_client_class_entry, client, ZEND_STRL("options"), 0, &z_options_tmp);
if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
num_options = zend_hash_num_elements(Z_ARRVAL_P(z_coptions));
}
ZVAL_UNDEF(&z_roptions);
zend_call_method_with_0_params(request, NULL, NULL, "getOptions", &z_roptions);
if (Z_TYPE(z_roptions) == IS_ARRAY) {
unsigned num = zend_hash_num_elements(Z_ARRVAL(z_roptions));
if (num > num_options) {
num_options = num;
}
}
ALLOC_HASHTABLE(options);
ZEND_INIT_SYMTABLE_EX(options, num_options, 0);
if (Z_TYPE_P(z_coptions) == IS_ARRAY) {
array_copy(Z_ARRVAL_P(z_coptions), options);
}
if (Z_TYPE(z_roptions) == IS_ARRAY) {
array_join(Z_ARRVAL(z_roptions), options, 0, 0);
}
zval_ptr_dtor(&z_roptions);
return options;
}
static void msg_queue_dtor(php_http_client_enqueue_t *e)
{
php_http_message_object_t *msg_obj = e->opaque;
zend_objects_store_del(&msg_obj->zo);
zend_hash_destroy(e->options);
FREE_HASHTABLE(e->options);
if (e->closure.fci.size) {
zval_ptr_dtor(&e->closure.fci.function_name);
if (e->closure.fci.object) {
zend_objects_store_del(e->closure.fci.object);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enqueue, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
ZEND_ARG_INFO(0, callable)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, enqueue)
{
zval *request;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
php_http_client_object_t *obj;
php_http_message_object_t *msg_obj;
php_http_client_enqueue_t q;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
msg_obj = PHP_HTTP_OBJ(NULL, request);
if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
php_http_throw(bad_method_call, "Failed to enqueue request; request already in queue", NULL);
return;
}
q.request = msg_obj->message;
q.options = combined_options(getThis(), request);
q.dtor = msg_queue_dtor;
q.opaque = msg_obj;
q.closure.fci = fci;
q.closure.fcc = fcc;
if (fci.size) {
Z_TRY_ADDREF(fci.function_name);
if (fci.object) {
++GC_REFCOUNT(fci.object);
}
}
Z_ADDREF_P(request);
php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
msg_queue_dtor(&q);
return;
);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_dequeue, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, dequeue)
{
zval *request;
php_http_client_object_t *obj;
php_http_message_object_t *msg_obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
msg_obj = PHP_HTTP_OBJ(NULL, request);
if (!php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
php_http_throw(bad_method_call, "Failed to dequeue request; request not in queue", NULL);
return;
}
php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_requeue, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
ZEND_ARG_INFO(0, callable)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, requeue)
{
zval *request;
zend_fcall_info fci = empty_fcall_info;
zend_fcall_info_cache fcc = empty_fcall_info_cache;
php_http_client_object_t *obj;
php_http_message_object_t *msg_obj;
php_http_client_enqueue_t q;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|f", &request, php_http_get_client_request_class_entry(), &fci, &fcc), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
msg_obj = PHP_HTTP_OBJ(NULL, request);
if (php_http_client_enqueued(obj->client, msg_obj->message, NULL)) {
php_http_expect(SUCCESS == php_http_client_dequeue(obj->client, msg_obj->message), runtime, return);
}
q.request = msg_obj->message;
q.options = combined_options(getThis(), request);
q.dtor = msg_queue_dtor;
q.opaque = msg_obj;
q.closure.fci = fci;
q.closure.fcc = fcc;
if (fci.size) {
Z_TRY_ADDREF(fci.function_name);
if (fci.object) {
++GC_REFCOUNT(fci.object);
}
}
Z_ADDREF_P(request);
php_http_expect(SUCCESS == php_http_client_enqueue(obj->client, &q), runtime,
msg_queue_dtor(&q);
return;
);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_count, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, count)
{
zend_long count_mode = -1;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
RETVAL_LONG(zend_llist_count(&obj->client->requests));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getResponse, 0, 0, 0)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getResponse)
{
zval *zrequest = NULL;
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &zrequest, php_http_get_client_request_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
if (zrequest) {
/* lookup the response with the request */
zend_llist_element *el = NULL;
php_http_message_object_t *req_obj = PHP_HTTP_OBJ(NULL, zrequest);
for (el = obj->client->responses.head; el; el = el->next) {
php_http_message_object_t *response_obj = *(php_http_message_object_t **) el->data;
if (response_obj->message->parent == req_obj->message) {
RETURN_OBJECT(&response_obj->zo, 1);
}
}
/* not found for the request! */
php_http_throw(unexpected_val, "Could not find response for the request", NULL);
return;
}
/* pop off the last response */
if (obj->client->responses.tail) {
php_http_message_object_t *response_obj = *(php_http_message_object_t **) obj->client->responses.tail->data;
/* pop off and go */
if (response_obj) {
RETVAL_OBJECT(&response_obj->zo, 1);
zend_llist_remove_tail(&obj->client->responses);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getHistory, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getHistory)
{
zval zhistory_tmp, *zhistory;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
zhistory = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("history"), 0, &zhistory_tmp);
RETVAL_ZVAL(zhistory, 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_send, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, send)
{
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(SUCCESS == php_http_client_exec(obj->client), runtime, return);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_once, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, once)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
RETURN_BOOL(0 < php_http_client_once(obj->client));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_wait, 0, 0, 0)
ZEND_ARG_INFO(0, timeout)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, wait)
{
double timeout = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|d", &timeout)) {
struct timeval timeout_val;
php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
timeout_val.tv_sec = (time_t) timeout;
timeout_val.tv_usec = PHP_HTTP_USEC(timeout) % PHP_HTTP_MCROSEC;
RETURN_BOOL(SUCCESS == php_http_client_wait(obj->client, timeout > 0 ? &timeout_val : NULL));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_configure, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, settings, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, configure)
{
HashTable *settings = NULL;
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H!", &settings), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_CONFIGURATION, settings), unexpected_val, return);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enablePipelining, 0, 0, 0)
ZEND_ARG_INFO(0, enable)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, enablePipelining)
{
zend_bool enable = 1;
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING, &enable), unexpected_val, return);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_enableEvents, 0, 0, 0)
ZEND_ARG_INFO(0, enable)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, enableEvents)
{
zend_bool enable = 1;
php_http_client_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &enable), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(SUCCESS == php_http_client_setopt(obj->client, PHP_HTTP_CLIENT_OPT_USE_EVENTS, &enable), unexpected_val, return);
RETVAL_ZVAL(getThis(), 1, 0);
}
struct notify_arg {
php_http_object_method_t *cb;
zval args[3];
int argc;
};
static int notify(zend_object_iterator *iter, void *puser)
{
zval *observer;
struct notify_arg *arg = puser;
if ((observer = iter->funcs->get_current_data(iter))) {
if (SUCCESS == php_http_object_method_call(arg->cb, observer, NULL, arg->argc, arg->args)) {
return ZEND_HASH_APPLY_KEEP;
}
}
return ZEND_HASH_APPLY_STOP;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_notify, 0, 0, 0)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, notify)
{
zval *request = NULL, *zprogress = NULL, observers_tmp, *observers;
php_http_client_object_t *client_obj;
struct notify_arg arg = {NULL};
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O!o!", &request, php_http_get_client_request_class_entry(), &zprogress), invalid_arg, return);
client_obj = PHP_HTTP_OBJ(NULL, getThis());
observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
if (Z_TYPE_P(observers) != IS_OBJECT) {
php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
return;
}
if (client_obj->update) {
arg.cb = client_obj->update;
ZVAL_COPY(&arg.args[0], getThis());
arg.argc = 1;
if (request) {
ZVAL_COPY(&arg.args[1], request);
arg.argc += 1;
}
if (zprogress) {
ZVAL_COPY(&arg.args[2], zprogress);
arg.argc += 1;
}
spl_iterator_apply(observers, notify, &arg);
zval_ptr_dtor(getThis());
if (request) {
zval_ptr_dtor(request);
}
if (zprogress) {
zval_ptr_dtor(zprogress);
}
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_attach, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, attach)
{
zval observers_tmp, *observers, *observer, retval;
php_http_client_object_t *client_obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
client_obj = PHP_HTTP_OBJ(NULL, getThis());
observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
if (Z_TYPE_P(observers) != IS_OBJECT) {
php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
return;
}
if (!client_obj->update) {
client_obj->update = php_http_object_method_init(NULL, observer, ZEND_STRL("update"));
}
ZVAL_UNDEF(&retval);
zend_call_method_with_1_params(observers, NULL, NULL, "attach", &retval, observer);
zval_ptr_dtor(&retval);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_detach, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, observer, SplObserver, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, detach)
{
zval observers_tmp, *observers, *observer, retval;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &observer, spl_ce_SplObserver), invalid_arg, return);
observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
if (Z_TYPE_P(observers) != IS_OBJECT) {
php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
return;
}
ZVAL_UNDEF(&retval);
zend_call_method_with_1_params(observers, NULL, NULL, "detach", &retval, observer);
zval_ptr_dtor(&retval);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getObservers, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getObservers)
{
zval observers_tmp, *observers;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
observers = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("observers"), 0, &observers_tmp);
if (Z_TYPE_P(observers) != IS_OBJECT) {
php_http_throw(unexpected_val, "Observer storage is corrupted", NULL);
return;
}
RETVAL_ZVAL(observers, 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getProgressInfo, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getProgressInfo)
{
zval *request;
php_http_client_object_t *obj;
php_http_message_object_t *req_obj;
php_http_client_progress_state_t *progress;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
req_obj = PHP_HTTP_OBJ(NULL, request);
php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, req_obj->message, &progress), unexpected_val, return);
object_init(return_value);
add_property_bool(return_value, "started", progress->started);
add_property_bool(return_value, "finished", progress->finished);
add_property_string(return_value, "info", STR_PTR(progress->info));
add_property_double(return_value, "dltotal", progress->dl.total);
add_property_double(return_value, "dlnow", progress->dl.now);
add_property_double(return_value, "ultotal", progress->ul.total);
add_property_double(return_value, "ulnow", progress->ul.now);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getTransferInfo, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, request, http\\Client\\Request, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getTransferInfo)
{
zval *request;
HashTable *info;
php_http_client_object_t *obj;
php_http_message_object_t *req_obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &request, php_http_get_client_request_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
req_obj = PHP_HTTP_OBJ(NULL, request);
object_init(return_value);
info = HASH_OF(return_value);
php_http_expect(SUCCESS == php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, req_obj->message, &info), unexpected_val, return);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, options, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, setOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set(getThis(), opts);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getOptions, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getOptions)
{
if (SUCCESS == zend_parse_parameters_none()) {
zval options_tmp, *options = zend_read_property(php_http_client_class_entry, getThis(), ZEND_STRL("options"), 0, &options_tmp);
RETVAL_ZVAL(options, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setSslOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, ssl_option, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, setSslOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addSslOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, addSslOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getSslOptions, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getSslOptions)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_setCookies, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, cookies, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, setCookies)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 1);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_addCookies, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, cookies, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, addCookies)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("cookies"), opts, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getCookies, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getCookies)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_options_get_subr(getThis(), ZEND_STRL("cookies"), return_value);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableDrivers, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getAvailableDrivers)
{
if (SUCCESS == zend_parse_parameters_none()) {
array_init(return_value);
php_http_client_driver_list(Z_ARRVAL_P(return_value));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableOptions, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getAvailableOptions)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
array_init(return_value);
php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, NULL, &Z_ARRVAL_P(return_value));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClient_getAvailableConfiguration, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClient, getAvailableConfiguration)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
array_init(return_value);
php_http_client_getopt(obj->client, PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION, NULL, &Z_ARRVAL_P(return_value));
}
}
static zend_function_entry php_http_client_methods[] = {
PHP_ME(HttpClient, __construct, ai_HttpClient_construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpClient, reset, ai_HttpClient_reset, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, enqueue, ai_HttpClient_enqueue, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, dequeue, ai_HttpClient_dequeue, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, requeue, ai_HttpClient_requeue, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, count, ai_HttpClient_count, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, send, ai_HttpClient_send, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, once, ai_HttpClient_once, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, wait, ai_HttpClient_wait, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getResponse, ai_HttpClient_getResponse, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getHistory, ai_HttpClient_getHistory, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, configure, ai_HttpClient_configure, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, enablePipelining, ai_HttpClient_enablePipelining, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
PHP_ME(HttpClient, enableEvents, ai_HttpClient_enableEvents, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED)
PHP_ME(HttpClient, notify, ai_HttpClient_notify, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, attach, ai_HttpClient_attach, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, detach, ai_HttpClient_detach, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getObservers, ai_HttpClient_getObservers, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getProgressInfo, ai_HttpClient_getProgressInfo, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getTransferInfo, ai_HttpClient_getTransferInfo, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, setOptions, ai_HttpClient_setOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getOptions, ai_HttpClient_getOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, setSslOptions, ai_HttpClient_setSslOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, addSslOptions, ai_HttpClient_addSslOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getSslOptions, ai_HttpClient_getSslOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, setCookies, ai_HttpClient_setCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, addCookies, ai_HttpClient_addCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getCookies, ai_HttpClient_getCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getAvailableDrivers, ai_HttpClient_getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpClient, getAvailableOptions, ai_HttpClient_getAvailableOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClient, getAvailableConfiguration, ai_HttpClient_getAvailableConfiguration, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_client)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Client", php_http_client_methods);
php_http_client_class_entry = zend_register_internal_class_ex(&ce, NULL);
php_http_client_class_entry->create_object = php_http_client_object_new;
zend_class_implements(php_http_client_class_entry, 2, spl_ce_SplSubject, spl_ce_Countable);
memcpy(&php_http_client_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_client_object_handlers.offset = XtOffsetOf(php_http_client_object_t, zo);
php_http_client_object_handlers.free_obj = php_http_client_object_free;
php_http_client_object_handlers.clone_obj = NULL;
zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("observers"), ZEND_ACC_PRIVATE);
zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_client_class_entry, ZEND_STRL("history"), ZEND_ACC_PROTECTED);
zend_declare_property_bool(php_http_client_class_entry, ZEND_STRL("recordHistory"), 0, ZEND_ACC_PUBLIC);
zend_hash_init(&php_http_client_drivers, 2, NULL, php_http_client_driver_hash_dtor, 1);
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(http_client)
{
zend_hash_destroy(&php_http_client_drivers);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client.h 0000644 0001750 0000144 00000014573 12667772426 016522 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_CLIENT_H
#define PHP_HTTP_CLIENT_H
typedef enum php_http_client_setopt_opt {
PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING,
PHP_HTTP_CLIENT_OPT_USE_EVENTS,
PHP_HTTP_CLIENT_OPT_CONFIGURATION,
} php_http_client_setopt_opt_t;
typedef enum php_http_client_getopt_opt {
PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, /* php_http_client_enqueue_t*, php_http_client_progress_state_t** */
PHP_HTTP_CLIENT_OPT_TRANSFER_INFO, /* php_http_client_enqueue_t*, HashTable* */
PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS, /* NULL, HashTable* */
PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION,/* NULL, HashTable */
} php_http_client_getopt_opt_t;
typedef struct php_http_client_enqueue {
php_http_message_t *request; /* unique */
HashTable *options;
void (*dtor)(struct php_http_client_enqueue *);
void *opaque;
struct {
zend_fcall_info fci;
zend_fcall_info_cache fcc;
} closure;
} php_http_client_enqueue_t;
typedef struct php_http_client *(*php_http_client_init_func_t)(struct php_http_client *p, void *init_arg);
typedef struct php_http_client *(*php_http_client_copy_func_t)(struct php_http_client *from, struct php_http_client *to);
typedef void (*php_http_client_dtor_func_t)(struct php_http_client *p);
typedef void (*php_http_client_reset_func_t)(struct php_http_client *p);
typedef ZEND_RESULT_CODE (*php_http_client_exec_func_t)(struct php_http_client *p);
typedef int (*php_http_client_once_func_t)(struct php_http_client *p);
typedef ZEND_RESULT_CODE (*php_http_client_wait_func_t)(struct php_http_client *p, struct timeval *custom_timeout);
typedef ZEND_RESULT_CODE (*php_http_client_enqueue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue);
typedef ZEND_RESULT_CODE (*php_http_client_dequeue_func_t)(struct php_http_client *p, php_http_client_enqueue_t *enqueue);
typedef ZEND_RESULT_CODE (*php_http_client_setopt_func_t)(struct php_http_client *p, php_http_client_setopt_opt_t opt, void *arg);
typedef ZEND_RESULT_CODE (*php_http_client_getopt_func_t)(struct php_http_client *h, php_http_client_getopt_opt_t opt, void *arg, void **res);
typedef struct php_http_client_ops {
php_resource_factory_ops_t *rsrc;
php_http_client_init_func_t init;
php_http_client_copy_func_t copy;
php_http_client_dtor_func_t dtor;
php_http_client_reset_func_t reset;
php_http_client_exec_func_t exec;
php_http_client_wait_func_t wait;
php_http_client_once_func_t once;
php_http_client_enqueue_func_t enqueue;
php_http_client_dequeue_func_t dequeue;
php_http_client_setopt_func_t setopt;
php_http_client_getopt_func_t getopt;
} php_http_client_ops_t;
typedef struct php_http_client_driver {
zend_string *driver_name;
zend_string *client_name;
zend_string *request_name;
php_http_client_ops_t *client_ops;
} php_http_client_driver_t;
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_driver_add(php_http_client_driver_t *driver);
PHP_HTTP_API php_http_client_driver_t *php_http_client_driver_get(zend_string *name);
typedef struct php_http_client_progress_state {
struct {
double now;
double total;
} ul;
struct {
double now;
double total;
} dl;
const char *info;
unsigned started:1;
unsigned finished:1;
} php_http_client_progress_state_t;
typedef ZEND_RESULT_CODE (*php_http_client_response_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_message_t **response);
typedef void (*php_http_client_progress_callback_t)(void *arg, struct php_http_client *client, php_http_client_enqueue_t *e, php_http_client_progress_state_t *state);
typedef struct php_http_client {
void *ctx;
php_resource_factory_t *rf;
php_http_client_ops_t *ops;
struct {
struct {
php_http_client_response_callback_t func;
void *arg;
} response;
struct {
php_http_client_progress_callback_t func;
void *arg;
} progress;
} callback;
zend_llist requests;
zend_llist responses;
} php_http_client_t;
PHP_HTTP_API zend_class_entry *php_http_client_get_class_entry();
typedef struct php_http_client_object {
php_http_client_t *client;
php_http_object_method_t *update;
php_http_object_method_t notify;
long iterator;
zend_object zo;
} php_http_client_object_t;
PHP_HTTP_API php_http_client_t *php_http_client_init(php_http_client_t *h, php_http_client_ops_t *ops, php_resource_factory_t *rf, void *init_arg);
PHP_HTTP_API php_http_client_t *php_http_client_copy(php_http_client_t *from, php_http_client_t *to);
PHP_HTTP_API void php_http_client_dtor(php_http_client_t *h);
PHP_HTTP_API void php_http_client_free(php_http_client_t **h);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_dequeue(php_http_client_t *h, php_http_message_t *request);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_wait(php_http_client_t *h, struct timeval *custom_timeout);
PHP_HTTP_API int php_http_client_once(php_http_client_t *h);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_exec(php_http_client_t *h);
PHP_HTTP_API void php_http_client_reset(php_http_client_t *h);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg);
PHP_HTTP_API ZEND_RESULT_CODE php_http_client_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void *res_ptr);
typedef int (*php_http_client_enqueue_cmp_func_t)(php_http_client_enqueue_t *cmp, void *arg);
/* compare with request message pointer if compare_func is NULL */
PHP_HTTP_API php_http_client_enqueue_t *php_http_client_enqueued(php_http_client_t *h, void *compare_arg, php_http_client_enqueue_cmp_func_t compare_func);
PHP_MINIT_FUNCTION(http_client);
PHP_MSHUTDOWN_FUNCTION(http_client);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_curl.c 0000644 0001750 0000144 00000247157 12667772426 017550 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include "php_http_client.h"
#if PHP_HTTP_HAVE_CURL
#if PHP_HTTP_HAVE_EVENT
# if !PHP_HTTP_HAVE_EVENT2 && /* just be really sure */ !(LIBEVENT_VERSION_NUMBER >= 0x02000000)
# include
# define event_base_new event_init
# define event_assign(e, b, s, a, cb, d) do {\
event_set(e, s, a, cb, d); \
event_base_set(b, e); \
} while(0)
# else
# if PHP_HTTP_HAVE_EVENT2
# include
# include
# else
# error "libevent presence is unknown"
# endif
# endif
# ifndef DBG_EVENTS
# define DBG_EVENTS 0
# endif
#endif
#ifdef PHP_HTTP_HAVE_OPENSSL
# include
#endif
#ifdef PHP_HTTP_HAVE_GNUTLS
# include
#endif
typedef struct php_http_client_curl {
CURLM *handle;
int unfinished; /* int because of curl_multi_perform() */
#if PHP_HTTP_HAVE_EVENT
struct event_base *evbase;
struct event *timeout;
unsigned useevents:1;
#endif
} php_http_client_curl_t;
typedef struct php_http_client_curl_handler {
CURL *handle;
php_resource_factory_t *rf;
php_http_client_t *client;
php_http_client_progress_state_t progress;
php_http_client_enqueue_t queue;
struct {
php_http_buffer_t headers;
php_http_message_body_t *body;
} response;
struct {
HashTable cache;
struct curl_slist *proxyheaders;
struct curl_slist *headers;
struct curl_slist *resolve;
php_http_buffer_t cookies;
php_http_buffer_t ranges;
struct {
uint count;
double delay;
} retry;
long redirects;
unsigned range_request:1;
unsigned encode_cookies:1;
} options;
} php_http_client_curl_handler_t;
typedef struct php_http_curle_storage {
char *url;
char *cookiestore;
CURLcode errorcode;
char errorbuffer[0x100];
} php_http_curle_storage_t;
static inline php_http_curle_storage_t *php_http_curle_get_storage(CURL *ch) {
php_http_curle_storage_t *st = NULL;
curl_easy_getinfo(ch, CURLINFO_PRIVATE, &st);
if (!st) {
st = pecalloc(1, sizeof(*st), 1);
curl_easy_setopt(ch, CURLOPT_PRIVATE, st);
curl_easy_setopt(ch, CURLOPT_ERRORBUFFER, st->errorbuffer);
}
return st;
}
static void *php_http_curle_ctor(void *opaque, void *init_arg)
{
void *ch;
if ((ch = curl_easy_init())) {
php_http_curle_get_storage(ch);
return ch;
}
return NULL;
}
static void *php_http_curle_copy(void *opaque, void *handle)
{
void *ch;
if ((ch = curl_easy_duphandle(handle))) {
curl_easy_reset(ch);
php_http_curle_get_storage(ch);
return ch;
}
return NULL;
}
static void php_http_curle_dtor(void *opaque, void *handle)
{
php_http_curle_storage_t *st = php_http_curle_get_storage(handle);
curl_easy_cleanup(handle);
if (st) {
if (st->url) {
pefree(st->url, 1);
}
if (st->cookiestore) {
pefree(st->cookiestore, 1);
}
pefree(st, 1);
}
}
static php_resource_factory_ops_t php_http_curle_resource_factory_ops = {
php_http_curle_ctor,
php_http_curle_copy,
php_http_curle_dtor
};
static void *php_http_curlm_ctor(void *opaque, void *init_arg)
{
return curl_multi_init();
}
static void php_http_curlm_dtor(void *opaque, void *handle)
{
curl_multi_cleanup(handle);
}
static php_resource_factory_ops_t php_http_curlm_resource_factory_ops = {
php_http_curlm_ctor,
NULL,
php_http_curlm_dtor
};
/* curl callbacks */
static size_t php_http_curle_read_callback(void *data, size_t len, size_t n, void *ctx)
{
php_http_message_body_t *body = ctx;
if (body && body->res) {
php_stream *s = php_http_message_body_stream(body);
if (s) {
return php_stream_read(s, data, len * n);
} else abort();
}
return 0;
}
#if PHP_HTTP_CURL_VERSION(7,32,0)
static int php_http_curle_xferinfo_callback(void *ctx, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
#else
static int php_http_curle_progress_callback(void *ctx, double dltotal, double dlnow, double ultotal, double ulnow)
#endif
{
php_http_client_curl_handler_t *h = ctx;
zend_bool update = 0;
if (h->progress.dl.total != dltotal
|| h->progress.dl.now != dlnow
|| h->progress.ul.total != ultotal
|| h->progress.ul.now != ulnow
) {
update = 1;
h->progress.dl.total = dltotal;
h->progress.dl.now = dlnow;
h->progress.ul.total = ultotal;
h->progress.ul.now = ulnow;
}
if (update && h->client->callback.progress.func) {
h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
}
return 0;
}
static int php_http_curle_seek_callback(void *userdata, curl_off_t offset, int origin)
{
php_http_message_body_t *body = userdata;
if (!body) {
return 1;
}
if (0 == php_stream_seek(php_http_message_body_stream(body), offset, origin)) {
return 0;
}
return 2;
}
static int php_http_curle_raw_callback(CURL *ch, curl_infotype type, char *data, size_t length, void *ctx)
{
php_http_client_curl_handler_t *h = ctx;
/* catch progress */
switch (type) {
case CURLINFO_TEXT:
if (data[0] == '-') {
} else if (php_memnstr(data, ZEND_STRL("Adding handle:"), data + length)) {
h->progress.info = "setup";
} else if (php_memnstr(data, ZEND_STRL("addHandle"), data + length)) {
h->progress.info = "setup";
} else if (php_memnstr(data, ZEND_STRL("About to connect"), data + length)) {
h->progress.info = "resolve";
} else if (php_memnstr(data, ZEND_STRL("Trying"), data + length)) {
h->progress.info = "connect";
} else if (php_memnstr(data, ZEND_STRL("Found bundle for host"), data + length)) {
h->progress.info = "connect";
} else if (php_memnstr(data, ZEND_STRL("Connected"), data + length)) {
h->progress.info = "connected";
} else if (php_memnstr(data, ZEND_STRL("Re-using existing connection!"), data + length)) {
h->progress.info = "connected";
} else if (php_memnstr(data, ZEND_STRL("blacklisted"), data + length)) {
h->progress.info = "blacklist check";
} else if (php_memnstr(data, ZEND_STRL("SSL"), data + length)) {
h->progress.info = "ssl negotiation";
} else if (php_memnstr(data, ZEND_STRL("upload"), data + length)) {
h->progress.info = "uploaded";
} else if (php_memnstr(data, ZEND_STRL("left intact"), data + length)) {
h->progress.info = "not disconnected";
} else if (php_memnstr(data, ZEND_STRL("closed"), data + length)) {
h->progress.info = "disconnected";
} else if (php_memnstr(data, ZEND_STRL("Issue another request"), data + length)) {
h->progress.info = "redirect";
} else if (php_memnstr(data, ZEND_STRL("Operation timed out"), data + length)) {
h->progress.info = "timeout";
} else {
#if 0
h->progress.info = data;
data[length - 1] = '\0';
#endif
}
if (h->client->callback.progress.func) {
h->client->callback.progress.func(h->client->callback.progress.arg, h->client, &h->queue, &h->progress);
}
break;
case CURLINFO_HEADER_OUT:
case CURLINFO_DATA_OUT:
case CURLINFO_SSL_DATA_OUT:
h->progress.info = "send";
break;
case CURLINFO_HEADER_IN:
case CURLINFO_DATA_IN:
case CURLINFO_SSL_DATA_IN:
h->progress.info = "receive";
break;
default:
break;
}
#if 0
/* debug */
_dpf(type, data, length);
#endif
return 0;
}
static int php_http_curle_header_callback(char *data, size_t n, size_t l, void *arg)
{
php_http_client_curl_handler_t *h = arg;
return php_http_buffer_append(&h->response.headers, data, n * l);
}
static int php_http_curle_body_callback(char *data, size_t n, size_t l, void *arg)
{
php_http_client_curl_handler_t *h = arg;
return php_http_message_body_append(h->response.body, data, n*l);
}
static ZEND_RESULT_CODE php_http_curle_get_info(CURL *ch, HashTable *info)
{
char *c = NULL;
long l = 0;
double d = 0;
struct curl_slist *s = NULL, *p = NULL;
zval tmp = {{0}};
/* BEGIN::CURLINFO */
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_EFFECTIVE_URL, &c)) {
ZVAL_STRING(&tmp, STR_PTR(c));
zend_hash_str_update(info, "effective_url", lenof("effective_url"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_RESPONSE_CODE, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "response_code", lenof("response_code"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TOTAL_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "total_time", lenof("total_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NAMELOOKUP_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "namelookup_time", lenof("namelookup_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONNECT_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "connect_time", lenof("connect_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRETRANSFER_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "pretransfer_time", lenof("pretransfer_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_UPLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "size_upload", lenof("size_upload"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SIZE_DOWNLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "size_download", lenof("size_download"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_DOWNLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "speed_download", lenof("speed_download"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SPEED_UPLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "speed_upload", lenof("speed_upload"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HEADER_SIZE, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "header_size", lenof("header_size"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REQUEST_SIZE, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "request_size", lenof("request_size"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_VERIFYRESULT, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "ssl_verifyresult", lenof("ssl_verifyresult"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_FILETIME, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "filetime", lenof("filetime"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "content_length_download", lenof("content_length_download"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_LENGTH_UPLOAD, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "content_length_upload", lenof("content_length_upload"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_STARTTRANSFER_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "starttransfer_time", lenof("starttransfer_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONTENT_TYPE, &c)) {
ZVAL_STRING(&tmp, STR_PTR(c));
zend_hash_str_update(info, "content_type", lenof("content_type"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "redirect_time", lenof("redirect_time"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_COUNT, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "redirect_count", lenof("redirect_count"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTP_CONNECTCODE, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "connect_code", lenof("connect_code"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_HTTPAUTH_AVAIL, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "httpauth_avail", lenof("httpauth_avail"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PROXYAUTH_AVAIL, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "proxyauth_avail", lenof("proxyauth_avail"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_OS_ERRNO, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "os_errno", lenof("os_errno"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_NUM_CONNECTS, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "num_connects", lenof("num_connects"), &tmp);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_SSL_ENGINES, &s)) {
array_init(&tmp);
for (p = s; p; p = p->next) {
if (p->data) {
add_next_index_string(&tmp, p->data);
}
}
zend_hash_str_update(info, "ssl_engines", lenof("ssl_engines"), &tmp);
curl_slist_free_all(s);
}
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_REDIRECT_URL, &c)) {
ZVAL_STRING(&tmp, STR_PTR(c));
zend_hash_str_update(info, "redirect_url", lenof("redirect_url"), &tmp);
}
#if PHP_HTTP_CURL_VERSION(7,19,0)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_IP, &c)) {
ZVAL_STRING(&tmp, STR_PTR(c));
zend_hash_str_update(info, "primary_ip", lenof("primary_ip"), &tmp);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,19,0)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_APPCONNECT_TIME, &d)) {
ZVAL_DOUBLE(&tmp, d);
zend_hash_str_update(info, "appconnect_time", lenof("appconnect_time"), &tmp);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,19,4)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CONDITION_UNMET, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "condition_unmet", lenof("condition_unmet"), &tmp);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,0)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_PRIMARY_PORT, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "primary_port", lenof("primary_port"), &tmp);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,0)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_IP, &c)) {
ZVAL_STRING(&tmp, STR_PTR(c));
zend_hash_str_update(info, "local_ip", lenof("local_ip"), &tmp);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,0)
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_LOCAL_PORT, &l)) {
ZVAL_LONG(&tmp, l);
zend_hash_str_update(info, "local_port", lenof("local_port"), &tmp);
}
#endif
/* END::CURLINFO */
#if PHP_HTTP_CURL_VERSION(7,34,0)
{
zval ti_array, subarray;
struct curl_tlssessioninfo *ti;
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_TLS_SESSION, &ti)) {
char *backend;
ZVAL_NULL(&subarray);
array_init(&ti_array);
switch (ti->backend) {
case CURLSSLBACKEND_NONE:
backend = "none";
break;
case CURLSSLBACKEND_OPENSSL:
backend = "openssl";
#ifdef PHP_HTTP_HAVE_OPENSSL
{
SSL_CTX *ctx = ti->internals;
array_init(&subarray);
add_assoc_long_ex(&subarray, ZEND_STRL("number"), SSL_CTX_sess_number(ctx));
add_assoc_long_ex(&subarray, ZEND_STRL("connect"), SSL_CTX_sess_connect(ctx));
add_assoc_long_ex(&subarray, ZEND_STRL("connect_good"), SSL_CTX_sess_connect_good(ctx));
add_assoc_long_ex(&subarray, ZEND_STRL("connect_renegotiate"), SSL_CTX_sess_connect_renegotiate(ctx));
add_assoc_long_ex(&subarray, ZEND_STRL("hits"), SSL_CTX_sess_hits(ctx));
add_assoc_long_ex(&subarray, ZEND_STRL("cache_full"), SSL_CTX_sess_cache_full(ctx));
}
#endif
break;
case CURLSSLBACKEND_GNUTLS:
backend = "gnutls";
#ifdef PHP_HTTP_HAVE_GNUTLS
{
gnutls_session_t sess = ti->internals;
char *desc;
array_init(&subarray);
if ((desc = gnutls_session_get_desc(sess))) {
add_assoc_string_ex(&subarray, ZEND_STRL("desc"), desc);
gnutls_free(desc);
}
add_assoc_bool_ex(&subarray, ZEND_STRL("resumed"), gnutls_session_is_resumed(sess));
}
#endif
break;
case CURLSSLBACKEND_NSS:
backend = "nss";
break;
#if !PHP_HTTP_CURL_VERSION(7,39,0)
case CURLSSLBACKEND_QSOSSL:
backend = "qsossl";
break;
#else
case CURLSSLBACKEND_GSKIT:
backend = "gskit";
break;
#endif
case CURLSSLBACKEND_POLARSSL:
backend = "polarssl";
break;
case CURLSSLBACKEND_CYASSL:
backend = "cyassl";
break;
case CURLSSLBACKEND_SCHANNEL:
backend = "schannel";
break;
case CURLSSLBACKEND_DARWINSSL:
backend = "darwinssl";
break;
default:
backend = "unknown";
}
add_assoc_string_ex(&ti_array, ZEND_STRL("backend"), backend);
add_assoc_zval_ex(&ti_array, ZEND_STRL("internals"), &subarray);
zend_hash_str_update(info, "tls_session", lenof("tls_session"), &ti_array);
}
}
#endif
#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT))
{
int i;
zval ci_array, subarray;
struct curl_certinfo *ci;
char *colon, *keyname;
if (CURLE_OK == curl_easy_getinfo(ch, CURLINFO_CERTINFO, &ci)) {
array_init(&ci_array);
for (i = 0; i < ci->num_of_certs; ++i) {
s = ci->certinfo[i];
array_init(&subarray);
for (p = s; p; p = p->next) {
if (p->data) {
if ((colon = strchr(p->data, ':'))) {
keyname = estrndup(p->data, colon - p->data);
add_assoc_string_ex(&subarray, keyname, colon - p->data, colon + 1);
efree(keyname);
} else {
add_next_index_string(&subarray, p->data);
}
}
}
add_next_index_zval(&ci_array, &subarray);
}
zend_hash_str_update(info, "certinfo", lenof("certinfo"), &ci_array);
}
}
#endif
{
php_http_curle_storage_t *st = php_http_curle_get_storage(ch);
ZVAL_LONG(&tmp, st->errorcode);
zend_hash_str_update(info, "curlcode", lenof("curlcode"), &tmp);
ZVAL_STRING(&tmp, st->errorbuffer);
zend_hash_str_update(info, "error", lenof("error"), &tmp);
}
return SUCCESS;
}
static int compare_queue(php_http_client_enqueue_t *e, void *handle)
{
return handle == ((php_http_client_curl_handler_t *) e->opaque)->handle;
}
static php_http_message_t *php_http_curlm_responseparser(php_http_client_curl_handler_t *h)
{
php_http_message_t *response;
php_http_header_parser_t parser;
zval *zh;
response = php_http_message_init(NULL, 0, h->response.body);
php_http_header_parser_init(&parser);
while (h->response.headers.used) {
php_http_header_parser_state_t st = php_http_header_parser_parse(&parser,
&h->response.headers, PHP_HTTP_HEADER_PARSER_CLEANUP, &response->hdrs,
(php_http_info_callback_t) php_http_message_info_callback, (void *) &response);
if (PHP_HTTP_HEADER_PARSER_STATE_FAILURE == st) {
break;
}
}
php_http_header_parser_dtor(&parser);
/* move body to right message */
if (response->body != h->response.body) {
php_http_message_t *ptr = response;
while (ptr->parent) {
ptr = ptr->parent;
}
php_http_message_body_free(&response->body);
response->body = ptr->body;
ptr->body = NULL;
}
php_http_message_body_addref(h->response.body);
/* let's update the response headers */
if ((zh = php_http_message_header(response, ZEND_STRL("Content-Length")))) {
Z_TRY_ADDREF_P(zh);
zend_hash_str_update(&response->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), zh);
}
if ((zh = php_http_message_header(response, ZEND_STRL("Transfer-Encoding")))) {
Z_TRY_ADDREF_P(zh);
zend_hash_str_update(&response->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), zh);
zend_hash_str_del(&response->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding"));
}
if ((zh = php_http_message_header(response, ZEND_STRL("Content-Range")))) {
Z_TRY_ADDREF_P(zh);
zend_hash_str_update(&response->hdrs, "X-Original-Content-Range", lenof("X-Original-Content-Range"), zh);
zend_hash_str_del(&response->hdrs, "Content-Range", lenof("Content-Range"));
}
if ((zh = php_http_message_header(response, ZEND_STRL("Content-Encoding")))) {
Z_TRY_ADDREF_P(zh);
zend_hash_str_update(&response->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), zh);
zend_hash_str_del(&response->hdrs, "Content-Encoding", lenof("Content-Encoding"));
}
php_http_message_update_headers(response);
return response;
}
static void php_http_curlm_responsehandler(php_http_client_t *context)
{
int err_count = 0, remaining = 0;
php_http_curle_storage_t *st, *err = NULL;
php_http_client_enqueue_t *enqueue;
php_http_client_curl_t *curl = context->ctx;
do {
CURLMsg *msg = curl_multi_info_read(curl->handle, &remaining);
if (msg && CURLMSG_DONE == msg->msg) {
if (CURLE_OK != msg->data.result) {
st = php_http_curle_get_storage(msg->easy_handle);
st->errorcode = msg->data.result;
/* defer the warnings/exceptions, so the callback is still called for this request */
if (!err) {
err = ecalloc(remaining + 1, sizeof(*err));
}
memcpy(&err[err_count], st, sizeof(*st));
if (st->url) {
err[err_count].url = estrdup(st->url);
}
err_count++;
}
if ((enqueue = php_http_client_enqueued(context, msg->easy_handle, compare_queue))) {
php_http_client_curl_handler_t *handler = enqueue->opaque;
php_http_message_t *response = php_http_curlm_responseparser(handler);
if (response) {
context->callback.response.func(context->callback.response.arg, context, &handler->queue, &response);
php_http_message_free(&response);
}
}
}
} while (remaining);
if (err_count) {
int i = 0;
do {
php_error_docref(NULL, E_WARNING, "%s; %s (%s)", curl_easy_strerror(err[i].errorcode), err[i].errorbuffer, STR_PTR(err[i].url));
if (err[i].url) {
efree(err[i].url);
}
} while (++i < err_count);
efree(err);
}
}
#if PHP_HTTP_HAVE_EVENT
typedef struct php_http_curlm_event {
struct event evnt;
php_http_client_t *context;
} php_http_curlm_event_t;
static inline int etoca(short action) {
switch (action & (EV_READ|EV_WRITE)) {
case EV_READ:
return CURL_CSELECT_IN;
break;
case EV_WRITE:
return CURL_CSELECT_OUT;
break;
case EV_READ|EV_WRITE:
return CURL_CSELECT_IN|CURL_CSELECT_OUT;
break;
default:
return 0;
}
}
static void php_http_curlm_timeout_callback(int socket, short action, void *event_data)
{
php_http_client_t *context = event_data;
php_http_client_curl_t *curl = context->ctx;
#if DBG_EVENTS
fprintf(stderr, "T");
#endif
if (curl->useevents) {
CURLMcode rc;
/* ignore and use -1,0 on timeout */
(void) socket;
(void) action;
while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, CURL_SOCKET_TIMEOUT, 0, &curl->unfinished)));
if (CURLM_OK != rc) {
php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
}
php_http_curlm_responsehandler(context);
}
}
static void php_http_curlm_event_callback(int socket, short action, void *event_data)
{
php_http_client_t *context = event_data;
php_http_client_curl_t *curl = context->ctx;
#if DBG_EVENTS
fprintf(stderr, "E");
#endif
if (curl->useevents) {
CURLMcode rc = CURLM_OK;
while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket_action(curl->handle, socket, etoca(action), &curl->unfinished)));
if (CURLM_OK != rc) {
php_error_docref(NULL, E_WARNING, "%s", curl_multi_strerror(rc));
}
php_http_curlm_responsehandler(context);
/* remove timeout if there are no transfers left */
if (!curl->unfinished && event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
event_del(curl->timeout);
}
}
}
static int php_http_curlm_socket_callback(CURL *easy, curl_socket_t sock, int action, void *socket_data, void *assign_data)
{
php_http_client_t *context = socket_data;
php_http_client_curl_t *curl = context->ctx;
#if DBG_EVENTS
fprintf(stderr, "S");
#endif
if (curl->useevents) {
int events = EV_PERSIST;
php_http_curlm_event_t *ev = assign_data;
if (!ev) {
ev = ecalloc(1, sizeof(php_http_curlm_event_t));
ev->context = context;
curl_multi_assign(curl->handle, sock, ev);
} else {
event_del(&ev->evnt);
}
switch (action) {
case CURL_POLL_IN:
events |= EV_READ;
break;
case CURL_POLL_OUT:
events |= EV_WRITE;
break;
case CURL_POLL_INOUT:
events |= EV_READ|EV_WRITE;
break;
case CURL_POLL_REMOVE:
efree(ev);
/* no break */
case CURL_POLL_NONE:
return 0;
default:
php_error_docref(NULL, E_WARNING, "Unknown socket action %d", action);
return -1;
}
event_assign(&ev->evnt, curl->evbase, sock, events, php_http_curlm_event_callback, context);
event_add(&ev->evnt, NULL);
}
return 0;
}
static void php_http_curlm_timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
{
php_http_client_t *context = timer_data;
php_http_client_curl_t *curl = context->ctx;
#if DBG_EVENTS
fprintf(stderr, "\ntimer <- timeout_ms: %ld\n", timeout_ms);
#endif
if (curl->useevents) {
if (timeout_ms < 0) {
php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, context);
} else if (timeout_ms > 0 || !event_initialized(curl->timeout) || !event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
struct timeval timeout;
if (!event_initialized(curl->timeout)) {
event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, context);
}
timeout.tv_sec = timeout_ms / 1000;
timeout.tv_usec = (timeout_ms % 1000) * 1000;
event_add(curl->timeout, &timeout);
}
}
}
#endif /* HAVE_EVENT */
/* curl options */
static php_http_options_t php_http_curle_options, php_http_curlm_options;
#define PHP_HTTP_CURLE_OPTION_CHECK_STRLEN 0x0001
#define PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR 0x0002
#define PHP_HTTP_CURLE_OPTION_TRANSFORM_MS 0x0004
static ZEND_RESULT_CODE php_http_curle_option_set_ssl_verifyhost(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_SSL_VERIFYHOST, Z_TYPE_P(val) == IS_TRUE ? 2 : 0)) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_cookiestore(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
if (storage->cookiestore) {
pefree(storage->cookiestore, 1);
}
if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) {
storage->cookiestore = pestrndup(Z_STRVAL_P(val), Z_STRLEN_P(val), 1);
} else {
storage->cookiestore = NULL;
}
if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEFILE, storage->cookiestore)
|| CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIEJAR, storage->cookiestore)
) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_cookies(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (val && Z_TYPE_P(val) != IS_NULL) {
HashTable *ht = HASH_OF(val);
if (curl->options.encode_cookies) {
if (SUCCESS == php_http_url_encode_hash_ex(ht, &curl->options.cookies, ZEND_STRL(";"), ZEND_STRL("="), NULL, 0)) {
php_http_buffer_fix(&curl->options.cookies);
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
return FAILURE;
}
} else {
return FAILURE;
}
} else {
php_http_arrkey_t cookie_key;
zval *cookie_val;
ZEND_HASH_FOREACH_KEY_VAL(ht, cookie_key.h, cookie_key.key, cookie_val)
{
zend_string *zs = zval_get_string(cookie_val);
php_http_arrkey_stringify(&cookie_key, NULL);
php_http_buffer_appendf(&curl->options.cookies, "%s=%s; ", cookie_key.key->val, zs->val);
php_http_arrkey_dtor(&cookie_key);
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
php_http_buffer_fix(&curl->options.cookies);
if (curl->options.cookies.used) {
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, curl->options.cookies.data)) {
return FAILURE;
}
}
}
} else {
php_http_buffer_reset(&curl->options.cookies);
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_COOKIE, NULL)) {
return FAILURE;
}
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_encodecookies(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
curl->options.encode_cookies = Z_TYPE_P(val) == IS_TRUE;
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_lastmodified(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (Z_LVAL_P(val)) {
if (Z_LVAL_P(val) > 0) {
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, Z_LVAL_P(val))) {
return FAILURE;
}
} else {
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, (long) sapi_get_request_time() + Z_LVAL_P(val))) {
return FAILURE;
}
}
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, (long) (curl->options.range_request ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE))) {
return FAILURE;
}
} else {
if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMEVALUE, 0)
|| CURLE_OK != curl_easy_setopt(ch, CURLOPT_TIMECONDITION, 0)
) {
return FAILURE;
}
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_compress(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
#if !PHP_HTTP_CURL_VERSION(7,21,6)
# define CURLOPT_ACCEPT_ENCODING CURLOPT_ENCODING
#endif
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_ACCEPT_ENCODING, Z_TYPE_P(val) == IS_TRUE ? "" : NULL)) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_etag(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
php_http_buffer_t header;
if (val && Z_TYPE_P(val) == IS_STRING && Z_STRLEN_P(val)) {
zend_bool is_quoted = !((Z_STRVAL_P(val)[0] != '"') || (Z_STRVAL_P(val)[Z_STRLEN_P(val)-1] != '"'));
php_http_buffer_init(&header);
php_http_buffer_appendf(&header, is_quoted?"%s: %s":"%s: \"%s\"", curl->options.range_request?"If-Match":"If-None-Match", Z_STRVAL_P(val));
php_http_buffer_fix(&header);
curl->options.headers = curl_slist_append(curl->options.headers, header.data);
php_http_buffer_dtor(&header);
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_range(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
php_http_buffer_reset(&curl->options.ranges);
if (val && Z_TYPE_P(val) != IS_NULL) {
zval *rr, *rb, *re;
zend_long rbl, rel;
HashTable *ht = HASH_OF(val);
ZEND_HASH_FOREACH_VAL(ht, rr)
{
if (Z_TYPE_P(rr) == IS_ARRAY) {
if (2 == php_http_array_list(Z_ARRVAL_P(rr), 2, &rb, &re)) {
if ( ((Z_TYPE_P(rb) == IS_LONG) || ((Z_TYPE_P(rb) == IS_STRING) && is_numeric_string(Z_STRVAL_P(rb), Z_STRLEN_P(rb), &rbl, NULL, 1))) &&
((Z_TYPE_P(re) == IS_LONG) || ((Z_TYPE_P(re) == IS_STRING) && is_numeric_string(Z_STRVAL_P(re), Z_STRLEN_P(re), &rel, NULL, 1)))) {
if ((rbl >= 0) && (rel >= 0)) {
php_http_buffer_appendf(&curl->options.ranges, "%ld-%ld,", rbl, rel);
}
}
}
}
}
ZEND_HASH_FOREACH_END();
if (curl->options.ranges.used) {
curl->options.range_request = 1;
/* ditch last comma */
curl->options.ranges.data[curl->options.ranges.used - 1] = '\0';
}
}
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RANGE, curl->options.ranges.data)) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_resume(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (Z_LVAL_P(val) > 0) {
curl->options.range_request = 1;
}
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESUME_FROM, Z_LVAL_P(val))) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_retrydelay(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
curl->options.retry.delay = Z_DVAL_P(val);
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_retrycount(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
curl->options.retry.count = Z_LVAL_P(val);
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_redirect(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_FOLLOWLOCATION, Z_LVAL_P(val) ? 1L : 0L)
|| CURLE_OK != curl_easy_setopt(ch, CURLOPT_MAXREDIRS, curl->options.redirects = Z_LVAL_P(val))
) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curle_option_set_portrange(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
long localport = 0, localportrange = 0;
if (val && Z_TYPE_P(val) != IS_NULL) {
zval *zps, *zpe;
switch (php_http_array_list(Z_ARRVAL_P(val), 2, &zps, &zpe)) {
case 2:
localportrange = labs(zval_get_long(zps)-zval_get_long(zpe))+1L;
/* no break */
case 1:
localport = (zval_get_long(zpe) > 0) ? MIN(zval_get_long(zps), zval_get_long(zpe)) : zval_get_long(zps);
break;
default:
break;
}
}
if ( CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORT, localport)
|| CURLE_OK != curl_easy_setopt(ch, CURLOPT_LOCALPORTRANGE, localportrange)
) {
return FAILURE;
}
return SUCCESS;
}
#if PHP_HTTP_CURL_VERSION(7,37,0)
static ZEND_RESULT_CODE php_http_curle_option_set_proxyheader(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
if (val && Z_TYPE_P(val) != IS_NULL) {
php_http_arrkey_t header_key;
zval *header_val;
php_http_buffer_t header;
php_http_buffer_init(&header);
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(val), header_key.h, header_key.key, header_val)
{
if (header_key.key) {
zend_string *zs = zval_get_string(header_val);
php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, zs->val);
zend_string_release(zs);
php_http_buffer_fix(&header);
curl->options.proxyheaders = curl_slist_append(curl->options.proxyheaders, header.data);
php_http_buffer_reset(&header);
}
}
ZEND_HASH_FOREACH_END();
php_http_buffer_dtor(&header);
}
if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, curl->options.proxyheaders)) {
return FAILURE;
}
if (CURLE_OK != curl_easy_setopt(curl->handle, CURLOPT_HEADEROPT, CURLHEADER_SEPARATE)) {
curl_easy_setopt(curl->handle, CURLOPT_PROXYHEADER, NULL);
return FAILURE;
}
return SUCCESS;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,3)
static ZEND_RESULT_CODE php_http_curle_option_set_resolve(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (val && Z_TYPE_P(val) != IS_NULL) {
HashTable *ht = HASH_OF(val);
zval *data;
ZEND_HASH_FOREACH_VAL(ht, data)
{
zend_string *zs = zval_get_string(data);
curl->options.resolve = curl_slist_append(curl->options.resolve, zs->val);
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, curl->options.resolve)) {
return FAILURE;
}
} else {
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_RESOLVE, NULL)) {
return FAILURE;
}
}
return SUCCESS;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP)
static ZEND_RESULT_CODE php_http_curle_option_set_ssl_tlsauthtype(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
if (val && Z_LVAL_P(val)) {
switch (Z_LVAL_P(val)) {
case CURL_TLSAUTH_SRP:
if (CURLE_OK == curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_CURL_TLSAUTH_SRP)) {
return SUCCESS;
}
/* no break */
default:
return FAILURE;
}
}
if (CURLE_OK != curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, PHP_HTTP_CURL_TLSAUTH_DEF)) {
return FAILURE;
}
return SUCCESS;
}
#endif
static void php_http_curle_options_init(php_http_options_t *registry)
{
php_http_option_t *opt;
/* url options */
#if PHP_HTTP_CURL_VERSION(7,42,0)
php_http_option_register(registry, ZEND_STRL("path_as_is"), CURLOPT_PATH_AS_IS, _IS_BOOL);
#endif
/* proxy */
if ((opt = php_http_option_register(registry, ZEND_STRL("proxyhost"), CURLOPT_PROXY, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
php_http_option_register(registry, ZEND_STRL("proxytype"), CURLOPT_PROXYTYPE, IS_LONG);
php_http_option_register(registry, ZEND_STRL("proxyport"), CURLOPT_PROXYPORT, IS_LONG);
if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauth"), CURLOPT_PROXYUSERPWD, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("proxyauthtype"), CURLOPT_PROXYAUTH, IS_LONG))) {
Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
}
php_http_option_register(registry, ZEND_STRL("proxytunnel"), CURLOPT_HTTPPROXYTUNNEL, _IS_BOOL);
#if PHP_HTTP_CURL_VERSION(7,19,4)
php_http_option_register(registry, ZEND_STRL("noproxy"), CURLOPT_NOPROXY, IS_STRING);
#endif
#if PHP_HTTP_CURL_VERSION(7,37,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("proxyheader"), CURLOPT_PROXYHEADER, IS_ARRAY))) {
opt->setter = php_http_curle_option_set_proxyheader;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,43,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("proxy_service_name"), CURLOPT_PROXY_SERVICE_NAME, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,40,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("unix_socket_path"), CURLOPT_UNIX_SOCKET_PATH, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
#endif
/* dns */
if ((opt = php_http_option_register(registry, ZEND_STRL("dns_cache_timeout"), CURLOPT_DNS_CACHE_TIMEOUT, IS_LONG))) {
Z_LVAL(opt->defval) = 60;
}
php_http_option_register(registry, ZEND_STRL("ipresolve"), CURLOPT_IPRESOLVE, IS_LONG);
#if PHP_HTTP_CURL_VERSION(7,21,3)
if ((opt = php_http_option_register(registry, ZEND_STRL("resolve"), CURLOPT_RESOLVE, IS_ARRAY))) {
opt->setter = php_http_curle_option_set_resolve;
}
#endif
#if PHP_HTTP_HAVE_ARES
# if PHP_HTTP_CURL_VERSION(7,24,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("dns_servers"), CURLOPT_DNS_SERVERS, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
# endif
# if PHP_HTTP_CURL_VERSION(7,33,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("dns_interface"), CURLOPT_DNS_INTERFACE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip4"), CURLOPT_DNS_LOCAL_IP4, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("dns_local_ip6"), CURLOPT_DNS_LOCAL_IP6, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
# endif
#endif
/* limits */
php_http_option_register(registry, ZEND_STRL("low_speed_limit"), CURLOPT_LOW_SPEED_LIMIT, IS_LONG);
php_http_option_register(registry, ZEND_STRL("low_speed_time"), CURLOPT_LOW_SPEED_TIME, IS_LONG);
/* LSF weirdance
php_http_option_register(registry, ZEND_STRL("max_send_speed"), CURLOPT_MAX_SEND_SPEED_LARGE, IS_LONG);
php_http_option_register(registry, ZEND_STRL("max_recv_speed"), CURLOPT_MAX_RECV_SPEED_LARGE, IS_LONG);
*/
/* connection handling */
/* crashes
if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLOPT_MAXCONNECTS, IS_LONG))) {
Z_LVAL(opt->defval) = 5;
}
*/
php_http_option_register(registry, ZEND_STRL("fresh_connect"), CURLOPT_FRESH_CONNECT, _IS_BOOL);
php_http_option_register(registry, ZEND_STRL("forbid_reuse"), CURLOPT_FORBID_REUSE, _IS_BOOL);
/* outgoing interface */
php_http_option_register(registry, ZEND_STRL("interface"), CURLOPT_INTERFACE, IS_STRING);
if ((opt = php_http_option_register(registry, ZEND_STRL("portrange"), CURLOPT_LOCALPORT, IS_ARRAY))) {
opt->setter = php_http_curle_option_set_portrange;
}
/* another endpoint port */
php_http_option_register(registry, ZEND_STRL("port"), CURLOPT_PORT, IS_LONG);
/* RFC4007 zone_id */
#if PHP_HTTP_CURL_VERSION(7,19,0)
php_http_option_register(registry, ZEND_STRL("address_scope"), CURLOPT_ADDRESS_SCOPE, IS_LONG);
#endif
/* auth */
if ((opt = php_http_option_register(registry, ZEND_STRL("httpauth"), CURLOPT_USERPWD, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("httpauthtype"), CURLOPT_HTTPAUTH, IS_LONG))) {
Z_LVAL(opt->defval) = CURLAUTH_ANYSAFE;
}
#if PHP_HTTP_CURL_VERSION(7,43,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("service_name"), CURLOPT_SERVICE_NAME, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
#endif
/* redirects */
if ((opt = php_http_option_register(registry, ZEND_STRL("redirect"), CURLOPT_FOLLOWLOCATION, IS_LONG))) {
opt->setter = php_http_curle_option_set_redirect;
}
php_http_option_register(registry, ZEND_STRL("unrestricted_auth"), CURLOPT_UNRESTRICTED_AUTH, _IS_BOOL);
#if PHP_HTTP_CURL_VERSION(7,19,1)
php_http_option_register(registry, ZEND_STRL("postredir"), CURLOPT_POSTREDIR, IS_LONG);
#endif
/* retries */
if ((opt = php_http_option_register(registry, ZEND_STRL("retrycount"), 0, IS_LONG))) {
opt->setter = php_http_curle_option_set_retrycount;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("retrydelay"), 0, IS_DOUBLE))) {
opt->setter = php_http_curle_option_set_retrydelay;
}
/* referer */
if ((opt = php_http_option_register(registry, ZEND_STRL("referer"), CURLOPT_REFERER, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("autoreferer"), CURLOPT_AUTOREFERER, _IS_BOOL))) {
ZVAL_BOOL(&opt->defval, 1);
}
/* useragent */
if ((opt = php_http_option_register(registry, ZEND_STRL("useragent"), CURLOPT_USERAGENT, IS_STRING))) {
/* don't check strlen, to allow sending no useragent at all */
ZVAL_PSTRING(&opt->defval,
"PECL_HTTP/" PHP_PECL_HTTP_VERSION " "
"PHP/" PHP_VERSION " "
"libcurl/" LIBCURL_VERSION);
}
/* resume */
if ((opt = php_http_option_register(registry, ZEND_STRL("resume"), CURLOPT_RESUME_FROM, IS_LONG))) {
opt->setter = php_http_curle_option_set_resume;
}
/* ranges */
if ((opt = php_http_option_register(registry, ZEND_STRL("range"), CURLOPT_RANGE, IS_ARRAY))) {
opt->setter = php_http_curle_option_set_range;
}
/* etag */
if ((opt = php_http_option_register(registry, ZEND_STRL("etag"), 0, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->setter = php_http_curle_option_set_etag;
}
/* compression */
if ((opt = php_http_option_register(registry, ZEND_STRL("compress"), 0, _IS_BOOL))) {
opt->setter = php_http_curle_option_set_compress;
}
/* lastmodified */
if ((opt = php_http_option_register(registry, ZEND_STRL("lastmodified"), 0, IS_LONG))) {
opt->setter = php_http_curle_option_set_lastmodified;
}
/* cookies */
if ((opt = php_http_option_register(registry, ZEND_STRL("encodecookies"), 0, _IS_BOOL))) {
opt->setter = php_http_curle_option_set_encodecookies;
ZVAL_BOOL(&opt->defval, 1);
}
if ((opt = php_http_option_register(registry, ZEND_STRL("cookies"), 0, IS_ARRAY))) {
opt->setter = php_http_curle_option_set_cookies;
}
/* cookiesession, don't load session cookies from cookiestore */
php_http_option_register(registry, ZEND_STRL("cookiesession"), CURLOPT_COOKIESESSION, _IS_BOOL);
/* cookiestore, read initial cookies from that file and store cookies back into that file */
if ((opt = php_http_option_register(registry, ZEND_STRL("cookiestore"), 0, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
opt->setter = php_http_curle_option_set_cookiestore;
}
/* maxfilesize */
php_http_option_register(registry, ZEND_STRL("maxfilesize"), CURLOPT_MAXFILESIZE, IS_LONG);
/* http protocol version */
php_http_option_register(registry, ZEND_STRL("protocol"), CURLOPT_HTTP_VERSION, IS_LONG);
/* timeouts */
if ((opt = php_http_option_register(registry, ZEND_STRL("timeout"), CURLOPT_TIMEOUT_MS, IS_DOUBLE))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("connecttimeout"), CURLOPT_CONNECTTIMEOUT_MS, IS_DOUBLE))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
Z_DVAL(opt->defval) = 3;
}
#if PHP_HTTP_CURL_VERSION(7,36,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("expect_100_timeout"), CURLOPT_EXPECT_100_TIMEOUT_MS, IS_DOUBLE))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_TRANSFORM_MS;
Z_DVAL(opt->defval) = 1;
}
#endif
/* tcp */
php_http_option_register(registry, ZEND_STRL("tcp_nodelay"), CURLOPT_TCP_NODELAY, _IS_BOOL);
#if PHP_HTTP_CURL_VERSION(7,25,0)
php_http_option_register(registry, ZEND_STRL("tcp_keepalive"), CURLOPT_TCP_KEEPALIVE, _IS_BOOL);
if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepidle"), CURLOPT_TCP_KEEPIDLE, IS_LONG))) {
Z_LVAL(opt->defval) = 60;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("tcp_keepintvl"), CURLOPT_TCP_KEEPINTVL, IS_LONG))) {
Z_LVAL(opt->defval) = 60;
}
#endif
/* ssl */
if ((opt = php_http_option_register(registry, ZEND_STRL("ssl"), 0, IS_ARRAY))) {
registry = &opt->suboptions;
if ((opt = php_http_option_register(registry, ZEND_STRL("cert"), CURLOPT_SSLCERT, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("certtype"), CURLOPT_SSLCERTTYPE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
ZVAL_PSTRING(&opt->defval, "PEM");
}
if ((opt = php_http_option_register(registry, ZEND_STRL("key"), CURLOPT_SSLKEY, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("keytype"), CURLOPT_SSLKEYTYPE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
ZVAL_PSTRING(&opt->defval, "PEM");
}
if ((opt = php_http_option_register(registry, ZEND_STRL("keypasswd"), CURLOPT_SSLKEYPASSWD, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
php_http_option_register(registry, ZEND_STRL("engine"), CURLOPT_SSLENGINE, IS_STRING);
php_http_option_register(registry, ZEND_STRL("version"), CURLOPT_SSLVERSION, IS_LONG);
if ((opt = php_http_option_register(registry, ZEND_STRL("verifypeer"), CURLOPT_SSL_VERIFYPEER, _IS_BOOL))) {
ZVAL_BOOL(&opt->defval, 1);
}
if ((opt = php_http_option_register(registry, ZEND_STRL("verifyhost"), CURLOPT_SSL_VERIFYHOST, _IS_BOOL))) {
ZVAL_BOOL(&opt->defval, 1);
opt->setter = php_http_curle_option_set_ssl_verifyhost;
}
#if PHP_HTTP_CURL_VERSION(7,41,0) && (defined(PHP_HTTP_HAVE_OPENSSL) || defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_GNUTLS))
php_http_option_register(registry, ZEND_STRL("verifystatus"), CURLOPT_SSL_VERIFYSTATUS, _IS_BOOL);
#endif
php_http_option_register(registry, ZEND_STRL("cipher_list"), CURLOPT_SSL_CIPHER_LIST, IS_STRING);
if ((opt = php_http_option_register(registry, ZEND_STRL("cainfo"), CURLOPT_CAINFO, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
#ifdef PHP_HTTP_CURL_CAINFO
ZVAL_PSTRING(&opt->defval, PHP_HTTP_CURL_CAINFO);
#endif
}
if ((opt = php_http_option_register(registry, ZEND_STRL("capath"), CURLOPT_CAPATH, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("random_file"), CURLOPT_RANDOM_FILE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("egdsocket"), CURLOPT_EGDSOCKET, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
#if PHP_HTTP_CURL_VERSION(7,19,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("issuercert"), CURLOPT_ISSUERCERT, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
# ifdef PHP_HTTP_HAVE_OPENSSL
if ((opt = php_http_option_register(registry, ZEND_STRL("crlfile"), CURLOPT_CRLFILE, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
# endif
#endif
#if (PHP_HTTP_CURL_VERSION(7,19,1) && defined(PHP_HTTP_HAVE_OPENSSL)) || (PHP_HTTP_CURL_VERSION(7,34,0) && defined(PHP_HTTP_HAVE_NSS)) || (PHP_HTTP_CURL_VERSION(7,42,0) && defined(PHP_HTTP_HAVE_GNUTLS)) || (PHP_HTTP_CURL_VERSION(7,39,0) && defined(PHP_HTTP_HAVE_GSKIT))
if ((opt = php_http_option_register(registry, ZEND_STRL("certinfo"), CURLOPT_CERTINFO, _IS_BOOL))) {
ZVAL_FALSE(&opt->defval);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,36,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("enable_npn"), CURLOPT_SSL_ENABLE_NPN, _IS_BOOL))) {
ZVAL_BOOL(&opt->defval, 1);
}
if ((opt = php_http_option_register(registry, ZEND_STRL("enable_alpn"), CURLOPT_SSL_ENABLE_ALPN, _IS_BOOL))) {
ZVAL_BOOL(&opt->defval, 1);
}
#endif
#if PHP_HTTP_CURL_VERSION(7,39,0)
/* FIXME: see http://curl.haxx.se/libcurl/c/CURLOPT_PINNEDPUBLICKEY.html#AVAILABILITY */
if ((opt = php_http_option_register(registry, ZEND_STRL("pinned_publickey"), CURLOPT_PINNEDPUBLICKEY, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP)
if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthtype"), CURLOPT_TLSAUTH_TYPE, IS_LONG))) {
opt->setter = php_http_curle_option_set_ssl_tlsauthtype;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthuser"), CURLOPT_TLSAUTH_USERNAME, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
if ((opt = php_http_option_register(registry, ZEND_STRL("tlsauthpass"), CURLOPT_TLSAUTH_PASSWORD, IS_STRING))) {
opt->flags |= PHP_HTTP_CURLE_OPTION_CHECK_STRLEN;
}
#endif
#if PHP_HTTP_CURL_VERSION(7,42,0) && (defined(PHP_HTTP_HAVE_NSS) || defined(PHP_HTTP_HAVE_DARWINSSL))
php_http_option_register(registry, ZEND_STRL("falsestart"), CURLOPT_SSL_FALSESTART, _IS_BOOL);
#endif
}
}
static zval *php_http_curle_get_option(php_http_option_t *opt, HashTable *options, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
zval *option;
if ((option = php_http_option_get(opt, options, NULL))) {
zval zopt;
ZVAL_DUP(&zopt, option);
convert_to_explicit_type(&zopt, opt->type);
zend_hash_update(&curl->options.cache, opt->name, &zopt);
return zend_hash_find(&curl->options.cache, opt->name);
}
return option;
}
static ZEND_RESULT_CODE php_http_curle_set_option(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_curl_handler_t *curl = userdata;
CURL *ch = curl->handle;
zval tmp;
CURLcode rc = CURLE_OK;
ZEND_RESULT_CODE rv = SUCCESS;
if (!val) {
val = &opt->defval;
}
switch (opt->type) {
case _IS_BOOL:
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) (Z_TYPE_P(val) == IS_TRUE))) {
rv = FAILURE;
}
break;
case IS_LONG:
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else if (CURLE_OK != curl_easy_setopt(ch, opt->option, Z_LVAL_P(val))) {
rv = FAILURE;
}
break;
case IS_STRING:
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else if (!val || Z_TYPE_P(val) == IS_NULL) {
if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
rv = FAILURE;
}
} else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_STRLEN) && !Z_STRLEN_P(val)) {
if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
rv = FAILURE;
}
} else if ((opt->flags & PHP_HTTP_CURLE_OPTION_CHECK_BASEDIR) && Z_STRVAL_P(val) && SUCCESS != php_check_open_basedir(Z_STRVAL_P(val))) {
if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, NULL))) {
rv = FAILURE;
}
} else if (CURLE_OK != (rc = curl_easy_setopt(ch, opt->option, Z_STRVAL_P(val)))) {
rv = FAILURE;
}
break;
case IS_DOUBLE:
if (opt->flags & PHP_HTTP_CURLE_OPTION_TRANSFORM_MS) {
tmp = *val;
Z_DVAL(tmp) *= 1000;
val = &tmp;
}
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else if (CURLE_OK != curl_easy_setopt(ch, opt->option, (long) Z_DVAL_P(val))) {
rv = FAILURE;
}
break;
case IS_ARRAY:
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else if (Z_TYPE_P(val) != IS_NULL) {
rv = php_http_options_apply(&opt->suboptions, Z_ARRVAL_P(val), curl);
}
break;
default:
if (opt->setter) {
rv = opt->setter(opt, val, curl);
} else {
rv = FAILURE;
}
break;
}
if (rv != SUCCESS) {
php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc));
}
return rv;
}
#if PHP_HTTP_CURL_VERSION(7,30,0)
static ZEND_RESULT_CODE php_http_curlm_option_set_pipelining_bl(php_http_option_t *opt, zval *value, void *userdata)
{
php_http_client_t *client = userdata;
php_http_client_curl_t *curl = client->ctx;
CURLM *ch = curl->handle;
HashTable tmp_ht;
char **bl = NULL;
/* array of char *, ending with a NULL */
if (value && Z_TYPE_P(value) != IS_NULL) {
zval *entry;
HashTable *ht = HASH_OF(value);
int c = zend_hash_num_elements(ht);
char **ptr = ecalloc(c + 1, sizeof(char *));
bl = ptr;
zend_hash_init(&tmp_ht, c, NULL, ZVAL_PTR_DTOR, 0);
array_join(ht, &tmp_ht, 0, ARRAY_JOIN_STRINGIFY);
ZEND_HASH_FOREACH_VAL(&tmp_ht, entry)
{
*ptr++ = Z_STRVAL_P(entry);
}
ZEND_HASH_FOREACH_END();
}
if (CURLM_OK != curl_multi_setopt(ch, opt->option, bl)) {
if (bl) {
efree(bl);
zend_hash_destroy(&tmp_ht);
}
return FAILURE;
}
if (bl) {
efree(bl);
zend_hash_destroy(&tmp_ht);
}
return SUCCESS;
}
#endif
#if PHP_HTTP_HAVE_EVENT
static inline ZEND_RESULT_CODE php_http_curlm_use_eventloop(php_http_client_t *h, zend_bool enable)
{
php_http_client_curl_t *curl = h->ctx;
if ((curl->useevents = enable)) {
if (!curl->evbase) {
curl->evbase = event_base_new();
}
if (!curl->timeout) {
curl->timeout = ecalloc(1, sizeof(struct event));
}
curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, h);
curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, php_http_curlm_socket_callback);
curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, h);
curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, php_http_curlm_timer_callback);
} else {
curl_multi_setopt(curl->handle, CURLMOPT_SOCKETDATA, NULL);
curl_multi_setopt(curl->handle, CURLMOPT_SOCKETFUNCTION, NULL);
curl_multi_setopt(curl->handle, CURLMOPT_TIMERDATA, NULL);
curl_multi_setopt(curl->handle, CURLMOPT_TIMERFUNCTION, NULL);
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_curlm_option_set_use_eventloop(php_http_option_t *opt, zval *value, void *userdata)
{
php_http_client_t *client = userdata;
return php_http_curlm_use_eventloop(client, value && Z_TYPE_P(value) == IS_TRUE);
}
#endif
static void php_http_curlm_options_init(php_http_options_t *registry)
{
php_http_option_t *opt;
/* set size of connection cache */
if ((opt = php_http_option_register(registry, ZEND_STRL("maxconnects"), CURLMOPT_MAXCONNECTS, IS_LONG))) {
/* -1 == default, 0 == unlimited */
ZVAL_LONG(&opt->defval, -1);
}
/* set max number of connections to a single host */
#if PHP_HTTP_CURL_VERSION(7,30,0)
php_http_option_register(registry, ZEND_STRL("max_host_connections"), CURLMOPT_MAX_HOST_CONNECTIONS, IS_LONG);
#endif
/* maximum number of requests in a pipeline */
#if PHP_HTTP_CURL_VERSION(7,30,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("max_pipeline_length"), CURLMOPT_MAX_PIPELINE_LENGTH, IS_LONG))) {
ZVAL_LONG(&opt->defval, 5);
}
#endif
/* max simultaneously open connections */
#if PHP_HTTP_CURL_VERSION(7,30,0)
php_http_option_register(registry, ZEND_STRL("max_total_connections"), CURLMOPT_MAX_TOTAL_CONNECTIONS, IS_LONG);
#endif
/* enable/disable HTTP pipelining */
php_http_option_register(registry, ZEND_STRL("pipelining"), CURLMOPT_PIPELINING, _IS_BOOL);
/* chunk length threshold for pipelining */
#if PHP_HTTP_CURL_VERSION(7,30,0)
php_http_option_register(registry, ZEND_STRL("chunk_length_penalty_size"), CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, IS_LONG);
#endif
/* size threshold for pipelining penalty */
#if PHP_HTTP_CURL_VERSION(7,30,0)
php_http_option_register(registry, ZEND_STRL("content_length_penalty_size"), CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, IS_LONG);
#endif
/* pipelining server blacklist */
#if PHP_HTTP_CURL_VERSION(7,30,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_server_bl"), CURLMOPT_PIPELINING_SERVER_BL, IS_ARRAY))) {
opt->setter = php_http_curlm_option_set_pipelining_bl;
}
#endif
/* pipelining host blacklist */
#if PHP_HTTP_CURL_VERSION(7,30,0)
if ((opt = php_http_option_register(registry, ZEND_STRL("pipelining_site_bl"), CURLMOPT_PIPELINING_SITE_BL, IS_ARRAY))) {
opt->setter = php_http_curlm_option_set_pipelining_bl;
}
#endif
/* events */
#if PHP_HTTP_HAVE_EVENT
if ((opt = php_http_option_register(registry, ZEND_STRL("use_eventloop"), 0, _IS_BOOL))) {
opt->setter = php_http_curlm_option_set_use_eventloop;
}
#endif
}
static ZEND_RESULT_CODE php_http_curlm_set_option(php_http_option_t *opt, zval *val, void *userdata)
{
php_http_client_t *client = userdata;
php_http_client_curl_t *curl = client->ctx;
CURLM *ch = curl->handle;
zval *orig = val;
CURLMcode rc = CURLM_UNKNOWN_OPTION;
ZEND_RESULT_CODE rv = SUCCESS;
if (!val) {
val = &opt->defval;
} else if (opt->type && Z_TYPE_P(val) != opt->type && !(Z_TYPE_P(val) == IS_NULL && opt->type == IS_ARRAY)) {
zval zopt;
ZVAL_DUP(&zopt, val);
convert_to_explicit_type(&zopt, opt->type);
val = &zopt;
}
if (opt->setter) {
rv = opt->setter(opt, val, client);
} else {
switch (opt->type) {
case _IS_BOOL:
if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, (long) zend_is_true(val)))) {
rv = FAILURE;
}
break;
case IS_LONG:
if (CURLM_OK != (rc = curl_multi_setopt(ch, opt->option, Z_LVAL_P(val)))) {
rv = FAILURE;
}
break;
default:
rv = FAILURE;
break;
}
}
if (val && val != orig && val != &opt->defval) {
zval_ptr_dtor(val);
}
if (rv != SUCCESS) {
php_error_docref(NULL, E_NOTICE, "Could not set option %s (%s)", opt->name->val, curl_easy_strerror(rc));
}
return rv;
}
/* client ops */
static ZEND_RESULT_CODE php_http_client_curl_handler_reset(php_http_client_curl_handler_t *curl)
{
CURL *ch = curl->handle;
php_http_curle_storage_t *st;
if ((st = php_http_curle_get_storage(ch))) {
if (st->url) {
pefree(st->url, 1);
st->url = NULL;
}
if (st->cookiestore) {
pefree(st->cookiestore, 1);
st->cookiestore = NULL;
}
st->errorbuffer[0] = '\0';
}
curl_easy_setopt(ch, CURLOPT_URL, NULL);
curl_easy_setopt(ch, CURLOPT_CUSTOMREQUEST, NULL);
curl_easy_setopt(ch, CURLOPT_HTTPGET, 1L);
curl_easy_setopt(ch, CURLOPT_NOBODY, 0L);
/* libcurl < 7.19.6 does not clear auth info with USERPWD set to NULL */
#if PHP_HTTP_CURL_VERSION(7,19,1)
curl_easy_setopt(ch, CURLOPT_PROXYUSERNAME, NULL);
curl_easy_setopt(ch, CURLOPT_PROXYPASSWORD, NULL);
curl_easy_setopt(ch, CURLOPT_USERNAME, NULL);
curl_easy_setopt(ch, CURLOPT_PASSWORD, NULL);
#endif
#if PHP_HTTP_CURL_VERSION(7,21,3)
if (curl->options.resolve) {
curl_slist_free_all(curl->options.resolve);
curl->options.resolve = NULL;
}
#endif
curl->options.retry.count = 0;
curl->options.retry.delay = 0;
curl->options.redirects = 0;
curl->options.encode_cookies = 1;
if (curl->options.headers) {
curl_slist_free_all(curl->options.headers);
curl->options.headers = NULL;
}
if (curl->options.proxyheaders) {
curl_slist_free_all(curl->options.proxyheaders);
curl->options.proxyheaders = NULL;
}
php_http_buffer_reset(&curl->options.cookies);
php_http_buffer_reset(&curl->options.ranges);
return SUCCESS;
}
static php_http_client_curl_handler_t *php_http_client_curl_handler_init(php_http_client_t *h, php_resource_factory_t *rf)
{
void *handle;
php_http_client_curl_handler_t *handler;
if (!(handle = php_resource_factory_handle_ctor(rf, NULL))) {
php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle");
return NULL;
}
handler = ecalloc(1, sizeof(*handler));
handler->rf = rf;
handler->client = h;
handler->handle = handle;
handler->response.body = php_http_message_body_init(NULL, NULL);
php_http_buffer_init(&handler->response.headers);
php_http_buffer_init(&handler->options.cookies);
php_http_buffer_init(&handler->options.ranges);
zend_hash_init(&handler->options.cache, 0, NULL, ZVAL_PTR_DTOR, 0);
#if defined(ZTS)
curl_easy_setopt(handle, CURLOPT_NOSIGNAL, 1L);
#endif
curl_easy_setopt(handle, CURLOPT_HEADER, 0L);
curl_easy_setopt(handle, CURLOPT_FILETIME, 1L);
curl_easy_setopt(handle, CURLOPT_AUTOREFERER, 1L);
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, php_http_curle_header_callback);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, php_http_curle_body_callback);
curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, php_http_curle_raw_callback);
curl_easy_setopt(handle, CURLOPT_READFUNCTION, php_http_curle_read_callback);
curl_easy_setopt(handle, CURLOPT_SEEKFUNCTION, php_http_curle_seek_callback);
#if PHP_HTTP_CURL_VERSION(7,32,0)
curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, php_http_curle_xferinfo_callback);
curl_easy_setopt(handle, CURLOPT_XFERINFODATA, handler);
#else
curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, php_http_curle_progress_callback);
curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, handler);
#endif
curl_easy_setopt(handle, CURLOPT_DEBUGDATA, handler);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, handler);
curl_easy_setopt(handle, CURLOPT_HEADERDATA, handler);
php_http_client_curl_handler_reset(handler);
return handler;
}
static ZEND_RESULT_CODE php_http_client_curl_handler_prepare(php_http_client_curl_handler_t *curl, php_http_client_enqueue_t *enqueue)
{
size_t body_size;
php_http_message_t *msg = enqueue->request;
php_http_curle_storage_t *storage = php_http_curle_get_storage(curl->handle);
/* request url */
if (!PHP_HTTP_INFO(msg).request.url) {
php_error_docref(NULL, E_WARNING, "Cannot request empty URL");
return FAILURE;
}
storage->errorbuffer[0] = '\0';
if (storage->url) {
pefree(storage->url, 1);
}
php_http_url_to_string(PHP_HTTP_INFO(msg).request.url, &storage->url, NULL, 1);
curl_easy_setopt(curl->handle, CURLOPT_URL, storage->url);
/* apply options */
php_http_options_apply(&php_http_curle_options, enqueue->options, curl);
/* request headers */
php_http_message_update_headers(msg);
if (zend_hash_num_elements(&msg->hdrs)) {
php_http_arrkey_t header_key;
zval *header_val;
zend_string *header_str;
php_http_buffer_t header;
#if !PHP_HTTP_CURL_VERSION(7,23,0)
zval *ct = zend_hash_str_find(&msg->hdrs, ZEND_STRL("Content-Length"));
#endif
php_http_buffer_init(&header);
ZEND_HASH_FOREACH_KEY_VAL(&msg->hdrs, header_key.h, header_key.key, header_val)
{
if (header_key.key) {
#if !PHP_HTTP_CURL_VERSION(7,23,0)
/* avoid duplicate content-length header */
if (ct && ct == header_val) {
continue;
}
#endif
header_str = zval_get_string(header_val);
php_http_buffer_appendf(&header, "%s: %s", header_key.key->val, header_str->val);
php_http_buffer_fix(&header);
curl->options.headers = curl_slist_append(curl->options.headers, header.data);
php_http_buffer_reset(&header);
zend_string_release(header_str);
}
}
ZEND_HASH_FOREACH_END();
php_http_buffer_dtor(&header);
}
curl_easy_setopt(curl->handle, CURLOPT_HTTPHEADER, curl->options.headers);
/* attach request body */
if ((body_size = php_http_message_body_size(msg->body))) {
/* RFC2616, section 4.3 (para. 4) states that Β»a message-body MUST NOT be included in a request if the
* specification of the request method (section 5.1.1) does not allow sending an entity-body in request.Β«
* Following the clause in section 5.1.1 (para. 2) that request methods Β»MUST be implemented with the
* same semantics as those specified in section 9Β« reveal that not any single defined HTTP/1.1 method
* does not allow a request body.
*/
php_stream_rewind(php_http_message_body_stream(msg->body));
curl_easy_setopt(curl->handle, CURLOPT_SEEKDATA, msg->body);
curl_easy_setopt(curl->handle, CURLOPT_READDATA, msg->body);
curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, body_size);
curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, body_size);
curl_easy_setopt(curl->handle, CURLOPT_POST, 1L);
} else {
curl_easy_setopt(curl->handle, CURLOPT_SEEKDATA, NULL);
curl_easy_setopt(curl->handle, CURLOPT_READDATA, NULL);
curl_easy_setopt(curl->handle, CURLOPT_INFILESIZE, 0L);
curl_easy_setopt(curl->handle, CURLOPT_POSTFIELDSIZE, 0L);
}
/*
* Always use CUSTOMREQUEST, else curl won't send any request body for GET etc.
* See e.g. bug #69313.
*
* Here's what curl does:
* - CURLOPT_HTTPGET: ignore request body
* - CURLOPT_UPLOAD: set "Expect: 100-continue" header
* - CURLOPT_POST: set "Content-Type: application/x-www-form-urlencoded" header
* Now select the least bad.
*
* See also https://tools.ietf.org/html/rfc7231#section-5.1.1
*/
if (PHP_HTTP_INFO(msg).request.method) {
switch(php_http_select_str(PHP_HTTP_INFO(msg).request.method, 2, "HEAD", "PUT")) {
case 0:
curl_easy_setopt(curl->handle, CURLOPT_NOBODY, 1L);
break;
case 1:
curl_easy_setopt(curl->handle, CURLOPT_UPLOAD, 1L);
break;
default:
curl_easy_setopt(curl->handle, CURLOPT_CUSTOMREQUEST, PHP_HTTP_INFO(msg).request.method);
}
} else {
php_error_docref(NULL, E_WARNING, "Cannot use empty request method");
return FAILURE;
}
return SUCCESS;
}
static void php_http_client_curl_handler_clear(php_http_client_curl_handler_t *handler)
{
curl_easy_setopt(handler->handle, CURLOPT_NOPROGRESS, 1L);
#if PHP_HTTP_CURL_VERSION(7,32,0)
curl_easy_setopt(handler->handle, CURLOPT_XFERINFOFUNCTION, NULL);
#else
curl_easy_setopt(handler->handle, CURLOPT_PROGRESSFUNCTION, NULL);
#endif
curl_easy_setopt(handler->handle, CURLOPT_VERBOSE, 0L);
curl_easy_setopt(handler->handle, CURLOPT_DEBUGFUNCTION, NULL);
}
static void php_http_client_curl_handler_dtor(php_http_client_curl_handler_t *handler)
{
php_http_client_curl_handler_clear(handler);
php_resource_factory_handle_dtor(handler->rf, handler->handle);
php_resource_factory_free(&handler->rf);
php_http_message_body_free(&handler->response.body);
php_http_buffer_dtor(&handler->response.headers);
php_http_buffer_dtor(&handler->options.ranges);
php_http_buffer_dtor(&handler->options.cookies);
zend_hash_destroy(&handler->options.cache);
#if PHP_HTTP_CURL_VERSION(7,21,3)
if (handler->options.resolve) {
curl_slist_free_all(handler->options.resolve);
handler->options.resolve = NULL;
}
#endif
if (handler->options.headers) {
curl_slist_free_all(handler->options.headers);
handler->options.headers = NULL;
}
if (handler->options.proxyheaders) {
curl_slist_free_all(handler->options.proxyheaders);
handler->options.proxyheaders = NULL;
}
efree(handler);
}
static php_http_client_t *php_http_client_curl_init(php_http_client_t *h, void *handle)
{
php_http_client_curl_t *curl;
if (!handle && !(handle = php_resource_factory_handle_ctor(h->rf, NULL))) {
php_error_docref(NULL, E_WARNING, "Failed to initialize curl handle");
return NULL;
}
curl = ecalloc(1, sizeof(*curl));
curl->handle = handle;
curl->unfinished = 0;
h->ctx = curl;
return h;
}
static void php_http_client_curl_dtor(php_http_client_t *h)
{
php_http_client_curl_t *curl = h->ctx;
#if PHP_HTTP_HAVE_EVENT
if (curl->timeout) {
if (event_initialized(curl->timeout) && event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
event_del(curl->timeout);
}
efree(curl->timeout);
curl->timeout = NULL;
}
if (curl->evbase) {
event_base_free(curl->evbase);
curl->evbase = NULL;
}
#endif
curl->unfinished = 0;
php_resource_factory_handle_dtor(h->rf, curl->handle);
efree(curl);
h->ctx = NULL;
}
static void queue_dtor(php_http_client_enqueue_t *e)
{
php_http_client_curl_handler_t *handler = e->opaque;
if (handler->queue.dtor) {
e->opaque = handler->queue.opaque;
handler->queue.dtor(e);
}
php_http_client_curl_handler_dtor(handler);
}
static php_resource_factory_t *create_rf(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
{
php_persistent_handle_factory_t *pf = NULL;
php_resource_factory_t *rf = NULL;
php_http_url_t *url = enqueue->request->http.info.request.url;
if (!url || (!url->host && !url->path)) {
php_error_docref(NULL, E_WARNING, "Cannot request empty URL");
return NULL;
}
/* only if the client itself is setup for persistence */
if (php_resource_factory_is_persistent(h->rf)) {
zend_string *id;
char *id_str = NULL;
size_t id_len;
int port = url->port ? url->port : 80;
zval *zport;
if ((zport = zend_hash_str_find(enqueue->options, ZEND_STRL("port")))) {
zend_long lport = zval_get_long(zport);
if (lport > 0) {
port = lport;
}
}
id_len = spprintf(&id_str, 0, "%s:%d", STR_PTR(url->host), port);
id = php_http_cs2zs(id_str, id_len);
pf = php_persistent_handle_concede(NULL, PHP_HTTP_G->client.curl.driver.request_name, id, NULL, NULL);
zend_string_release(id);
}
if (pf) {
rf = php_persistent_handle_resource_factory_init(NULL, pf);
} else {
rf = php_resource_factory_init(NULL, &php_http_curle_resource_factory_ops, NULL, NULL);
}
return rf;
}
static ZEND_RESULT_CODE php_http_client_curl_enqueue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
{
CURLMcode rs;
php_http_client_curl_t *curl = h->ctx;
php_http_client_curl_handler_t *handler;
php_http_client_progress_state_t *progress;
php_resource_factory_t *rf;
rf = create_rf(h, enqueue);
if (!rf) {
return FAILURE;
}
handler = php_http_client_curl_handler_init(h, rf);
if (!handler) {
return FAILURE;
}
if (SUCCESS != php_http_client_curl_handler_prepare(handler, enqueue)) {
php_http_client_curl_handler_dtor(handler);
return FAILURE;
}
handler->queue = *enqueue;
enqueue->opaque = handler;
enqueue->dtor = queue_dtor;
if (CURLM_OK == (rs = curl_multi_add_handle(curl->handle, handler->handle))) {
zend_llist_add_element(&h->requests, enqueue);
++curl->unfinished;
if (h->callback.progress.func && SUCCESS == php_http_client_getopt(h, PHP_HTTP_CLIENT_OPT_PROGRESS_INFO, enqueue->request, &progress)) {
progress->info = "start";
h->callback.progress.func(h->callback.progress.arg, h, &handler->queue, progress);
progress->started = 1;
}
return SUCCESS;
} else {
php_error_docref(NULL, E_WARNING, "Could not enqueue request: %s", curl_multi_strerror(rs));
return FAILURE;
}
}
static ZEND_RESULT_CODE php_http_client_curl_dequeue(php_http_client_t *h, php_http_client_enqueue_t *enqueue)
{
CURLMcode rs;
php_http_client_curl_t *curl = h->ctx;
php_http_client_curl_handler_t *handler = enqueue->opaque;
php_http_client_curl_handler_clear(handler);
if (CURLM_OK == (rs = curl_multi_remove_handle(curl->handle, handler->handle))) {
zend_llist_del_element(&h->requests, handler->handle, (int (*)(void *, void *)) compare_queue);
return SUCCESS;
} else {
php_error_docref(NULL, E_WARNING, "Could not dequeue request: %s", curl_multi_strerror(rs));
}
return FAILURE;
}
static void php_http_client_curl_reset(php_http_client_t *h)
{
zend_llist_element *next_el, *this_el;
for (this_el = h->requests.head; this_el; this_el = next_el) {
next_el = this_el->next;
php_http_client_curl_dequeue(h, (void *) this_el->data);
}
}
static inline void php_http_client_curl_get_timeout(php_http_client_curl_t *curl, long max_tout, struct timeval *timeout)
{
if ((CURLM_OK == curl_multi_timeout(curl->handle, &max_tout)) && (max_tout > 0)) {
timeout->tv_sec = max_tout / 1000;
timeout->tv_usec = (max_tout % 1000) * 1000;
} else {
timeout->tv_sec = 0;
timeout->tv_usec = 1000;
}
}
#ifdef PHP_WIN32
# define SELECT_ERROR SOCKET_ERROR
#else
# define SELECT_ERROR -1
#endif
static ZEND_RESULT_CODE php_http_client_curl_wait(php_http_client_t *h, struct timeval *custom_timeout)
{
int MAX;
fd_set R, W, E;
struct timeval timeout;
php_http_client_curl_t *curl = h->ctx;
#if PHP_HTTP_HAVE_EVENT
if (curl->useevents) {
if (!event_initialized(curl->timeout)) {
event_assign(curl->timeout, curl->evbase, CURL_SOCKET_TIMEOUT, 0, php_http_curlm_timeout_callback, h);
} else if (custom_timeout && timerisset(custom_timeout)) {
event_add(curl->timeout, custom_timeout);
} else if (!event_pending(curl->timeout, EV_TIMEOUT, NULL)) {
php_http_client_curl_get_timeout(curl, 1000, &timeout);
event_add(curl->timeout, &timeout);
}
event_base_loop(curl->evbase, EVLOOP_ONCE);
return SUCCESS;
}
#endif
FD_ZERO(&R);
FD_ZERO(&W);
FD_ZERO(&E);
if (CURLM_OK == curl_multi_fdset(curl->handle, &R, &W, &E, &MAX)) {
if (custom_timeout && timerisset(custom_timeout)) {
timeout = *custom_timeout;
} else {
php_http_client_curl_get_timeout(curl, 1000, &timeout);
}
if (MAX == -1) {
php_http_sleep((double) timeout.tv_sec + (double) (timeout.tv_usec / PHP_HTTP_MCROSEC));
return SUCCESS;
} else if (SELECT_ERROR != select(MAX + 1, &R, &W, &E, &timeout)) {
return SUCCESS;
}
}
return FAILURE;
}
static int php_http_client_curl_once(php_http_client_t *h)
{
php_http_client_curl_t *curl = h->ctx;
#if PHP_HTTP_HAVE_EVENT
if (curl->useevents) {
event_base_loop(curl->evbase, EVLOOP_NONBLOCK);
} else
#endif
while (CURLM_CALL_MULTI_PERFORM == curl_multi_perform(curl->handle, &curl->unfinished));
php_http_curlm_responsehandler(h);
return curl->unfinished;
}
static ZEND_RESULT_CODE php_http_client_curl_exec(php_http_client_t *h)
{
#if PHP_HTTP_HAVE_EVENT
php_http_client_curl_t *curl = h->ctx;
if (curl->useevents) {
php_http_curlm_timeout_callback(CURL_SOCKET_TIMEOUT, /*EV_READ|EV_WRITE*/0, h);
do {
int ev_rc = event_base_dispatch(curl->evbase);
#if DBG_EVENTS
fprintf(stderr, "%c", "X.0"[ev_rc+1]);
#endif
if (ev_rc < 0) {
php_error_docref(NULL, E_ERROR, "Error in event_base_dispatch()");
return FAILURE;
}
} while (curl->unfinished && !EG(exception));
} else
#endif
{
while (php_http_client_curl_once(h) && !EG(exception)) {
if (SUCCESS != php_http_client_curl_wait(h, NULL)) {
#ifdef PHP_WIN32
/* see http://msdn.microsoft.com/library/en-us/winsock/winsock/windows_sockets_error_codes_2.asp */
php_error_docref(NULL, E_WARNING, "WinSock error: %d", WSAGetLastError());
#else
php_error_docref(NULL, E_WARNING, "%s", strerror(errno));
#endif
return FAILURE;
}
}
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_client_curl_setopt(php_http_client_t *h, php_http_client_setopt_opt_t opt, void *arg)
{
php_http_client_curl_t *curl = h->ctx;
switch (opt) {
case PHP_HTTP_CLIENT_OPT_CONFIGURATION:
return php_http_options_apply(&php_http_curlm_options, (HashTable *) arg, h);
break;
case PHP_HTTP_CLIENT_OPT_ENABLE_PIPELINING:
if (CURLM_OK != curl_multi_setopt(curl->handle, CURLMOPT_PIPELINING, (long) *((zend_bool *) arg))) {
return FAILURE;
}
break;
case PHP_HTTP_CLIENT_OPT_USE_EVENTS:
#if PHP_HTTP_HAVE_EVENT
return php_http_curlm_use_eventloop(h, *(zend_bool *) arg);
break;
#endif
default:
return FAILURE;
}
return SUCCESS;
}
static int apply_available_options(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key)
{
php_http_option_t *opt = Z_PTR_P(pDest);
HashTable *ht;
zval entry;
int c;
ht = va_arg(args, HashTable*);
if ((c = zend_hash_num_elements(&opt->suboptions.options))) {
array_init_size(&entry, c);
zend_hash_apply_with_arguments(&opt->suboptions.options, apply_available_options, 1, Z_ARRVAL(entry));
} else {
/* catch deliberate NULL options */
if (Z_TYPE(opt->defval) == IS_STRING && !Z_STRVAL(opt->defval)) {
ZVAL_NULL(&entry);
} else {
ZVAL_ZVAL(&entry, &opt->defval, 1, 0);
}
}
if (hash_key->key) {
zend_hash_update(ht, hash_key->key, &entry);
} else {
zend_hash_index_update(ht, hash_key->h, &entry);
}
return ZEND_HASH_APPLY_KEEP;
}
static ZEND_RESULT_CODE php_http_client_curl_getopt(php_http_client_t *h, php_http_client_getopt_opt_t opt, void *arg, void **res)
{
php_http_client_enqueue_t *enqueue;
switch (opt) {
case PHP_HTTP_CLIENT_OPT_PROGRESS_INFO:
if ((enqueue = php_http_client_enqueued(h, arg, NULL))) {
php_http_client_curl_handler_t *handler = enqueue->opaque;
*((php_http_client_progress_state_t **) res) = &handler->progress;
return SUCCESS;
}
break;
case PHP_HTTP_CLIENT_OPT_TRANSFER_INFO:
if ((enqueue = php_http_client_enqueued(h, arg, NULL))) {
php_http_client_curl_handler_t *handler = enqueue->opaque;
php_http_curle_get_info(handler->handle, *(HashTable **) res);
return SUCCESS;
}
break;
case PHP_HTTP_CLIENT_OPT_AVAILABLE_OPTIONS:
zend_hash_apply_with_arguments(&php_http_curle_options.options, apply_available_options, 1, *(HashTable **) res);
break;
case PHP_HTTP_CLIENT_OPT_AVAILABLE_CONFIGURATION:
zend_hash_apply_with_arguments(&php_http_curlm_options.options, apply_available_options, 1, *(HashTable **) res);
break;
default:
break;
}
return FAILURE;
}
static php_http_client_ops_t php_http_client_curl_ops = {
&php_http_curlm_resource_factory_ops,
php_http_client_curl_init,
NULL /* copy */,
php_http_client_curl_dtor,
php_http_client_curl_reset,
php_http_client_curl_exec,
php_http_client_curl_wait,
php_http_client_curl_once,
php_http_client_curl_enqueue,
php_http_client_curl_dequeue,
php_http_client_curl_setopt,
php_http_client_curl_getopt
};
php_http_client_ops_t *php_http_client_curl_get_ops(void)
{
return &php_http_client_curl_ops;
}
PHP_MINIT_FUNCTION(http_client_curl)
{
php_http_options_t *options;
PHP_HTTP_G->client.curl.driver.driver_name = zend_string_init(ZEND_STRL("curl"), 1);
PHP_HTTP_G->client.curl.driver.client_name = zend_string_init(ZEND_STRL("http\\Client\\Curl"), 1);
PHP_HTTP_G->client.curl.driver.request_name = zend_string_init(ZEND_STRL("http\\Client\\Curl\\Request"), 1);
PHP_HTTP_G->client.curl.driver.client_ops = &php_http_client_curl_ops;
if (SUCCESS != php_http_client_driver_add(&PHP_HTTP_G->client.curl.driver)) {
return FAILURE;
}
if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.client_name, &php_http_curlm_resource_factory_ops, NULL, NULL)) {
return FAILURE;
}
if (SUCCESS != php_persistent_handle_provide(PHP_HTTP_G->client.curl.driver.request_name, &php_http_curle_resource_factory_ops, NULL, NULL)) {
return FAILURE;
}
if ((options = php_http_options_init(&php_http_curle_options, 1))) {
options->getter = php_http_curle_get_option;
options->setter = php_http_curle_set_option;
php_http_curle_options_init(options);
}
if ((options = php_http_options_init(&php_http_curlm_options, 1))) {
options->getter = php_http_option_get;
options->setter = php_http_curlm_set_option;
php_http_curlm_options_init(options);
}
/*
* HTTP Protocol Version Constants
*/
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_0", CURL_HTTP_VERSION_1_0, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_1_1", CURL_HTTP_VERSION_1_1, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,33,0)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2_0", CURL_HTTP_VERSION_2_0, CONST_CS|CONST_PERSISTENT);
#endif
#if PHP_HTTP_CURL_VERSION(7,47,0)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_2TLS", CURL_HTTP_VERSION_2TLS, CONST_CS|CONST_PERSISTENT);
#endif
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "HTTP_VERSION_ANY", CURL_HTTP_VERSION_NONE, CONST_CS|CONST_PERSISTENT);
/*
* SSL Version Constants
*/
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1", CURL_SSLVERSION_TLSv1, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,34,0)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_0", CURL_SSLVERSION_TLSv1_0, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_1", CURL_SSLVERSION_TLSv1_1, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_TLSv1_2", CURL_SSLVERSION_TLSv1_2, CONST_CS|CONST_PERSISTENT);
#endif
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv2", CURL_SSLVERSION_SSLv2, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_SSLv3", CURL_SSLVERSION_SSLv3, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "SSL_VERSION_ANY", CURL_SSLVERSION_DEFAULT, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,21,4) && defined(PHP_HTTP_CURL_TLSAUTH_SRP)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "TLSAUTH_SRP", CURL_TLSAUTH_SRP, CONST_CS|CONST_PERSISTENT);
#endif
/*
* DNS IPvX resolving
*/
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V4", CURL_IPRESOLVE_V4, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_V6", CURL_IPRESOLVE_V6, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "IPRESOLVE_ANY", CURL_IPRESOLVE_WHATEVER, CONST_CS|CONST_PERSISTENT);
/*
* Auth Constants
*/
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_BASIC", CURLAUTH_BASIC, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,19,3)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_DIGEST_IE", CURLAUTH_DIGEST_IE, CONST_CS|CONST_PERSISTENT);
#endif
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_NTLM", CURLAUTH_NTLM, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_GSSNEG", CURLAUTH_GSSNEGOTIATE, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,38,0)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_SPNEGO", CURLAUTH_NEGOTIATE, CONST_CS|CONST_PERSISTENT);
#endif
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "AUTH_ANY", CURLAUTH_ANY, CONST_CS|CONST_PERSISTENT);
/*
* Proxy Type Constants
*/
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4", CURLPROXY_SOCKS4, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS4A", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5_HOSTNAME", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_SOCKS5", CURLPROXY_SOCKS5, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP", CURLPROXY_HTTP, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,19,4)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "PROXY_HTTP_1_0", CURLPROXY_HTTP_1_0, CONST_CS|CONST_PERSISTENT);
#endif
/*
* Post Redirection Constants
*/
#if PHP_HTTP_CURL_VERSION(7,19,1)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_301", CURL_REDIR_POST_301, CONST_CS|CONST_PERSISTENT);
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_302", CURL_REDIR_POST_302, CONST_CS|CONST_PERSISTENT);
#if PHP_HTTP_CURL_VERSION(7,26,0)
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_303", CURL_REDIR_POST_303, CONST_CS|CONST_PERSISTENT);
#endif
REGISTER_NS_LONG_CONSTANT("http\\Client\\Curl", "POSTREDIR_ALL", CURL_REDIR_POST_ALL, CONST_CS|CONST_PERSISTENT);
#endif
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(http_client_curl)
{
php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.client_name, NULL);
php_persistent_handle_cleanup(PHP_HTTP_G->client.curl.driver.request_name, NULL);
zend_string_release(PHP_HTTP_G->client.curl.driver.client_name);
zend_string_release(PHP_HTTP_G->client.curl.driver.request_name);
zend_string_release(PHP_HTTP_G->client.curl.driver.driver_name);
php_http_options_dtor(&php_http_curle_options);
php_http_options_dtor(&php_http_curlm_options);
return SUCCESS;
}
#endif /* PHP_HTTP_HAVE_CURL */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_curl.h 0000644 0001750 0000144 00000002153 12667772426 017536 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_CLIENT_CURL_H
#define PHP_HTTP_CLIENT_CURL_H
#if PHP_HTTP_HAVE_CURL
struct php_http_client_curl_globals {
php_http_client_driver_t driver;
};
PHP_MINIT_FUNCTION(http_client_curl);
PHP_MSHUTDOWN_FUNCTION(http_client_curl);
#endif /* PHP_HTTP_HAVE_CURL */
#endif /* PHP_HTTP_CLIENT_CURL_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_request.c 0000644 0001750 0000144 00000023212 12667772426 020253 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static zend_class_entry *php_http_client_request_class_entry;
zend_class_entry *php_http_get_client_request_class_entry(void)
{
return php_http_client_request_class_entry;
}
void php_http_client_options_set_subr(zval *this_ptr, char *key, size_t len, zval *opts, int overwrite);
void php_http_client_options_set(zval *this_ptr, zval *opts);
void php_http_client_options_get_subr(zval *this_ptr, char *key, size_t len, zval *return_value);
#define PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj) \
do { \
if (!obj->message) { \
obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL); \
} \
} while(0)
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest___construct, 0, 0, 0)
ZEND_ARG_INFO(0, method)
ZEND_ARG_INFO(0, url)
ZEND_ARG_ARRAY_INFO(0, headers, 1)
ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, __construct)
{
char *meth_str = NULL;
size_t meth_len = 0;
zval *zheaders = NULL, *zbody = NULL, *zurl = NULL;
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!z!a!O!", &meth_str, &meth_len, &zurl, &zheaders, &zbody, php_http_get_message_body_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->message) {
php_http_message_set_type(obj->message, PHP_HTTP_REQUEST);
} else {
obj->message = php_http_message_init(NULL, PHP_HTTP_REQUEST, NULL);
}
if (zbody) {
php_http_expect(SUCCESS == php_http_message_object_set_body(obj, zbody), unexpected_val, return);
}
if (meth_str && meth_len) {
PHP_HTTP_INFO(obj->message).request.method = estrndup(meth_str, meth_len);
}
if (zurl) {
PHP_HTTP_INFO(obj->message).request.url = php_http_url_from_zval(zurl, ~0);
}
if (zheaders) {
array_copy(Z_ARRVAL_P(zheaders), &obj->message->hdrs);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setContentType, 0, 0, 1)
ZEND_ARG_INFO(0, content_type)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, setContentType)
{
zend_string *ct_str;
php_http_message_object_t *obj;
zval zct;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "S", &ct_str), invalid_arg, return);
if (ct_str->len && !strchr(ct_str->val, '/')) {
php_http_throw(unexpected_val, "Content type \"%s\" does not seem to contain a primary and a secondary part", ct_str->val);
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj);
ZVAL_STR_COPY(&zct, ct_str);
zend_hash_str_update(&obj->message->hdrs, "Content-Type", lenof("Content-Type"), &zct);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getContentType, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, getContentType)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
zval *zct;
PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj);
php_http_message_update_headers(obj->message);
zct = php_http_message_header(obj->message, ZEND_STRL("Content-Type"));
if (zct) {
RETURN_ZVAL(zct, 1, 0);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setQuery, 0, 0, 0)
ZEND_ARG_INFO(0, query_data)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, setQuery)
{
zval *qdata = NULL, arr, str;
php_http_message_object_t *obj;
php_http_url_t *old_url = NULL, new_url = {NULL};
unsigned flags = PHP_HTTP_URL_REPLACE;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!", &qdata), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj);
ZVAL_NULL(&str);
if (qdata) {
array_init(&arr);
php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str), bad_querystring,
zval_dtor(&arr);
return;
);
new_url.query = Z_STRVAL(str);
zval_dtor(&arr);
} else {
flags = PHP_HTTP_URL_STRIP_QUERY;
}
if (obj->message->http.info.request.url) {
old_url = obj->message->http.info.request.url;
}
obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, flags);
if (old_url) {
php_http_url_free(&old_url);
}
zval_ptr_dtor(&str);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getQuery, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, getQuery)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj);
if (obj->message->http.info.request.url && obj->message->http.info.request.url->query) {
RETVAL_STRING(obj->message->http.info.request.url->query);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addQuery, 0, 0, 1)
ZEND_ARG_INFO(0, query_data)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, addQuery)
{
zval *qdata, arr, str;
php_http_message_object_t *obj;
php_http_url_t *old_url = NULL, new_url = {NULL};
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &qdata), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_CLIENT_REQUEST_OBJECT_INIT(obj);
array_init(&arr);
ZVAL_NULL(&str);
php_http_expect(SUCCESS == php_http_querystring_update(&arr, qdata, &str), bad_querystring,
zval_dtor(&arr);
return;
);
new_url.query = Z_STRVAL(str);
zval_dtor(&arr);
if (obj->message->http.info.request.url) {
old_url = obj->message->http.info.request.url;
}
obj->message->http.info.request.url = php_http_url_mod(old_url, &new_url, PHP_HTTP_URL_JOIN_QUERY);
if (old_url) {
php_http_url_free(&old_url);
}
zval_ptr_dtor(&str);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, options, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, setOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set(getThis(), opts);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getOptions, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, getOptions)
{
if (SUCCESS == zend_parse_parameters_none()) {
zval tmp, *zoptions = zend_read_property(php_http_client_request_class_entry, getThis(), ZEND_STRL("options"), 0, &tmp);
RETURN_ZVAL(zoptions, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_setSslOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, setSslOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 1);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_addSslOptions, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, ssl_options, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, addSslOptions)
{
zval *opts = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!/", &opts), invalid_arg, return);
php_http_client_options_set_subr(getThis(), ZEND_STRL("ssl"), opts, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientRequest_getSslOptions, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientRequest, getSslOptions)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_client_options_get_subr(getThis(), ZEND_STRL("ssl"), return_value);
}
}
static zend_function_entry php_http_client_request_methods[] = {
PHP_ME(HttpClientRequest, __construct, ai_HttpClientRequest___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpClientRequest, setContentType, ai_HttpClientRequest_setContentType, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, getContentType, ai_HttpClientRequest_getContentType, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, setQuery, ai_HttpClientRequest_setQuery, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, getQuery, ai_HttpClientRequest_getQuery, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, addQuery, ai_HttpClientRequest_addQuery, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, setOptions, ai_HttpClientRequest_setOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, getOptions, ai_HttpClientRequest_getOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, setSslOptions, ai_HttpClientRequest_setSslOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, getSslOptions, ai_HttpClientRequest_getSslOptions, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientRequest, addSslOptions, ai_HttpClientRequest_addSslOptions, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_client_request)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Request", php_http_client_request_methods);
php_http_client_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry());
zend_declare_property_null(php_http_client_request_class_entry, ZEND_STRL("options"), ZEND_ACC_PROTECTED);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_request.h 0000644 0001750 0000144 00000002027 12667772426 020261 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_CLIENT_REQUEST_H
#define PHP_HTTP_CLIENT_REQUEST_H
PHP_HTTP_API zend_class_entry *php_http_get_client_request_class_entry(void);
PHP_MINIT_FUNCTION(http_client_request);
#endif /* PHP_HTTP_CLIENT_REQUEST_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_response.c 0000644 0001750 0000144 00000011216 12667772426 020422 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static zend_class_entry *php_http_client_response_class_entry;
zend_class_entry *php_http_get_client_response_class_entry(void)
{
return php_http_client_response_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getCookies, 0, 0, 0)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(0, allowed_extras)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientResponse, getCookies)
{
zend_long flags = 0;
zval *allowed_extras_array = NULL;
int i = 0;
char **allowed_extras = NULL;
zval *header = NULL, *entry = NULL;
php_http_message_object_t *msg;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|la!/", &flags, &allowed_extras_array)) {
return;
}
msg = PHP_HTTP_OBJ(NULL, getThis());
array_init(return_value);
if (allowed_extras_array) {
/* FIXME: use zend_string** instead of char** */
allowed_extras = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(allowed_extras_array)) + 1, sizeof(char *));
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(allowed_extras_array), entry)
{
zend_string *zs = zval_get_string(entry);
allowed_extras[i++] = estrndup(zs->val, zs->len);
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
}
if ((header = php_http_message_header(msg->message, ZEND_STRL("Set-Cookie")))) {
php_http_cookie_list_t *list;
if (Z_TYPE_P(header) == IS_ARRAY) {
zval *single_header;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), single_header)
{
zend_string *zs = zval_get_string(single_header);
if ((list = php_http_cookie_list_parse(NULL, zs->val, zs->len, flags, allowed_extras))) {
zval cookie;
ZVAL_OBJ(&cookie, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo);
add_next_index_zval(return_value, &cookie);
}
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
} else {
zend_string *zs = zval_get_string(header);
if ((list = php_http_cookie_list_parse(NULL, zs->val, zs->len, flags, allowed_extras))) {
zval cookie;
ZVAL_OBJ(&cookie, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo);
add_next_index_zval(return_value, &cookie);
}
zend_string_release(zs);
}
}
if (allowed_extras) {
for (i = 0; allowed_extras[i]; ++i) {
efree(allowed_extras[i]);
}
efree(allowed_extras);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpClientResponse_getTransferInfo, 0, 0, 0)
ZEND_ARG_INFO(0, element)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpClientResponse, getTransferInfo)
{
char *info_name = NULL;
size_t info_len = 0;
zval info_tmp, info_name_tmp, *info;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &info_name, &info_len), invalid_arg, return);
info = zend_read_property(php_http_client_response_class_entry, getThis(), ZEND_STRL("transferInfo"), 0, &info_tmp);
/* request completed? */
if (Z_TYPE_P(info) != IS_OBJECT) {
php_http_throw(bad_method_call, "Incomplete state", NULL);
return;
}
if (info_len && info_name) {
info = zend_read_property(NULL, info, php_http_pretty_key(info_name, info_len, 0, 0), info_len, 0, &info_name_tmp);
if (!info) {
php_http_throw(unexpected_val, "Could not find transfer info with name '%s'", info_name);
return;
}
}
RETURN_ZVAL(info, 1, 0);
}
static zend_function_entry php_http_client_response_methods[] = {
PHP_ME(HttpClientResponse, getCookies, ai_HttpClientResponse_getCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpClientResponse, getTransferInfo, ai_HttpClientResponse_getTransferInfo, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_client_response)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Client", "Response", php_http_client_response_methods);
php_http_client_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry());
zend_declare_property_null(php_http_client_response_class_entry, ZEND_STRL("transferInfo"), ZEND_ACC_PROTECTED);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_client_response.h 0000644 0001750 0000144 00000002035 12667772426 020426 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_CLIENT_RESPONSE_H
#define PHP_HTTP_CLIENT_RESPONSE_H
PHP_HTTP_API zend_class_entry *php_http_get_client_response_class_entry(void);
PHP_MINIT_FUNCTION(http_client_response);
#endif /* PHP_HTTP_CLIENT_RESPONSE_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_cookie.c 0000644 0001750 0000144 00000070325 12667772426 016505 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list)
{
if (!list) {
list = emalloc(sizeof(*list));
}
zend_hash_init(&list->cookies, 0, NULL, ZVAL_PTR_DTOR, 0);
zend_hash_init(&list->extras, 0, NULL, ZVAL_PTR_DTOR, 0);
list->path = NULL;
list->domain = NULL;
list->expires = -1;
list->max_age = -1;
list->flags = 0;
return list;
}
php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to)
{
to = php_http_cookie_list_init(to);
array_copy(&from->cookies, &to->cookies);
array_copy(&from->extras, &to->extras);
PTR_SET(to->path, from->path ? estrdup(from->path) : NULL);
PTR_SET(to->domain, from->domain ? estrdup(from->domain) : NULL);
to->expires = from->expires;
to->max_age = from->max_age;
to->flags = from->flags;
return to;
}
void php_http_cookie_list_dtor(php_http_cookie_list_t *list)
{
if (list) {
zend_hash_destroy(&list->cookies);
zend_hash_destroy(&list->extras);
PTR_SET(list->path, NULL);
PTR_SET(list->domain, NULL);
}
}
void php_http_cookie_list_free(php_http_cookie_list_t **list)
{
if (*list) {
php_http_cookie_list_dtor(*list);
efree(*list);
*list = NULL;
}
}
const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *zcookie)
{
zval *cookie = zend_symtable_str_find(&list->cookies, name, name_len);
if (!cookie || (Z_TYPE_P(cookie) != IS_STRING)) {
return NULL;
}
if (zcookie) {
*zcookie = *cookie;
}
return Z_STRVAL_P(cookie);
}
const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *zextra)
{
zval *extra = zend_symtable_str_find(&list->extras, name, name_len);
if (!extra || (Z_TYPE_P(extra) != IS_STRING)) {
return NULL;
}
if (zextra) {
*zextra = *extra;
}
return Z_STRVAL_P(extra);
}
void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len)
{
zval cookie_value;
ZVAL_STRINGL(&cookie_value, value, value_len);
zend_symtable_str_update(&list->cookies, name, name_len, &cookie_value);
}
void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len)
{
zval extra_value;
ZVAL_STRINGL(&extra_value, value, value_len);
zend_symtable_str_update(&list->extras, name, name_len, &extra_value);
}
#define _KEY_IS(s) (key->key && key->key->len == sizeof(s)-1 && !strncasecmp(key->key->val, (s), key->key->len))
static void add_entry(php_http_cookie_list_t *list, char **allowed_extras, long flags, zend_hash_key *key, zval *val)
{
zval arg;
ZVAL_DUP(&arg, val);
convert_to_string(&arg);
if (!(flags & PHP_HTTP_COOKIE_PARSE_RAW)) {
Z_STRLEN(arg) = php_raw_url_decode(Z_STRVAL(arg), Z_STRLEN(arg));
zend_string_forget_hash_val(Z_STR(arg));
}
if _KEY_IS("path") {
PTR_SET(list->path, estrndup(Z_STRVAL(arg), Z_STRLEN(arg)));
} else if _KEY_IS("domain") {
PTR_SET(list->domain, estrndup(Z_STRVAL(arg), Z_STRLEN(arg)));
} else if _KEY_IS("expires") {
char *date = estrndup(Z_STRVAL(arg), Z_STRLEN(arg));
list->expires = php_parse_date(date, NULL);
efree(date);
} else if _KEY_IS("max-age") {
list->max_age = zval_get_long(val);
} else if _KEY_IS("secure") {
list->flags |= PHP_HTTP_COOKIE_SECURE;
} else if _KEY_IS("httpOnly") {
list->flags |= PHP_HTTP_COOKIE_HTTPONLY;
} else {
php_http_arrkey_t tmp = {0};
php_http_arrkey_stringify(&tmp, key);
/* check for extra */
if (allowed_extras) {
char **ae = allowed_extras;
for (; *ae; ++ae) {
if (!strncasecmp(*ae, tmp.key->val, tmp.key->len)) {
zend_symtable_update(&list->extras, tmp.key, &arg);
php_http_arrkey_dtor(&tmp);
return;
}
}
}
/* cookie */
zend_symtable_update(&list->cookies, tmp.key, &arg);
php_http_arrkey_dtor(&tmp);
return;
}
zval_ptr_dtor(&arg);
}
php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras)
{
php_http_params_opts_t opts;
HashTable params;
zend_hash_key k, arg_k;
zval *param, *val, *args, *arg;
php_http_params_opts_default_get(&opts);
opts.input.str = estrndup(str, len);
opts.input.len = len;
opts.param = NULL;
zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0);
php_http_params_parse(¶ms, &opts);
efree(opts.input.str);
list = php_http_cookie_list_init(list);
ZEND_HASH_FOREACH_KEY_VAL(¶ms, k.h, k.key, param)
{
if (Z_TYPE_P(param) == IS_ARRAY) {
if ((val = zend_hash_str_find(Z_ARRVAL_P(param), ZEND_STRL("value")))) {
add_entry(list, NULL, flags, &k, val);
}
if ((args = zend_hash_str_find(Z_ARRVAL_P(param), ZEND_STRL("arguments"))) && Z_TYPE_P(args) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(args), arg_k.h, arg_k.key, arg)
{
add_entry(list, allowed_extras, flags, &arg_k, arg);
}
ZEND_HASH_FOREACH_END();
}
}
}
ZEND_HASH_FOREACH_END();
zend_hash_destroy(¶ms);
return list;
}
void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct)
{
zval cookies, extras, tmp;
HashTable *ht = HASH_OF(strct);
array_init_size(&cookies, zend_hash_num_elements(&list->cookies));
array_copy(&list->cookies, Z_ARRVAL(cookies));
zend_symtable_str_update(ht, ZEND_STRL("cookies"), &cookies);
array_init_size(&extras, zend_hash_num_elements(&list->extras));
array_copy(&list->extras, Z_ARRVAL(extras));
zend_symtable_str_update(ht, ZEND_STRL("extras"), &extras);
ZVAL_LONG(&tmp, list->flags);
zend_symtable_str_update(ht, ZEND_STRL("flags"), &tmp);
ZVAL_LONG(&tmp, list->expires);
zend_symtable_str_update(ht, ZEND_STRL("expires"), &tmp);
ZVAL_LONG(&tmp, list->max_age);
zend_symtable_str_update(ht, ZEND_STRL("max-age"), &tmp);
ZVAL_STRING(&tmp, STR_PTR(list->path));
zend_symtable_str_update(ht, ZEND_STRL("path"), &tmp);
ZVAL_STRING(&tmp, STR_PTR(list->domain));
zend_symtable_str_update(ht, ZEND_STRL("domain"), &tmp);
}
php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct)
{
zval *tmp;
HashTable *ht;
ht = HASH_OF(strct);
list = php_http_cookie_list_init(list);
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("cookies"))) && Z_TYPE_P(tmp) == IS_ARRAY){
array_copy(Z_ARRVAL_P(tmp), &list->cookies);
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("extras"))) && Z_TYPE_P(tmp) == IS_ARRAY){
array_copy(Z_ARRVAL_P(tmp), &list->extras);
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("flags")))) {
list->flags = zval_get_long(tmp);
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("expires")))) {
if (Z_TYPE_P(tmp) == IS_LONG) {
list->expires = Z_LVAL_P(tmp);
} else {
zend_long lval;
zend_string *lstr = zval_get_string(tmp);
if (IS_LONG == is_numeric_string(lstr->val, lstr->len, &lval, NULL, 0)) {
list->expires = lval;
} else {
list->expires = php_parse_date(lstr->val, NULL);
}
zend_string_release(lstr);
}
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("max-age")))) {
if (Z_TYPE_P(tmp) == IS_LONG) {
list->max_age = Z_LVAL_P(tmp);
} else {
zend_long lval;
zend_string *lstr = zval_get_string(tmp);
if (IS_LONG == is_numeric_string(lstr->val, lstr->len, &lval, NULL, 0)) {
list->max_age = lval;
}
zend_string_release(lstr);
}
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) {
zend_string *str = zval_get_string(tmp);
list->path = estrndup(str->val, str->len);
zend_string_release(str);
}
if ((tmp = zend_hash_str_find_ind(ht, ZEND_STRL("domain")))) {
zend_string *str = zval_get_string(tmp);
list->domain = estrndup(str->val, str->len);
zend_string_release(str);
}
return list;
}
static inline void append_encoded(php_http_buffer_t *buf, const char *key, size_t key_len, const char *val, size_t val_len)
{
zend_string *enc_str[2];
enc_str[0] = php_raw_url_encode(key, key_len);
enc_str[1] = php_raw_url_encode(val, val_len);
php_http_buffer_append(buf, enc_str[0]->val, enc_str[0]->len);
php_http_buffer_appends(buf, "=");
php_http_buffer_append(buf, enc_str[1]->val, enc_str[1]->len);
php_http_buffer_appends(buf, "; ");
zend_string_release(enc_str[0]);
zend_string_release(enc_str[1]);
}
void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len)
{
php_http_buffer_t buf;
zend_hash_key key;
zval *val;
php_http_buffer_init(&buf);
ZEND_HASH_FOREACH_KEY_VAL(&list->cookies, key.h, key.key, val)
{
zend_string *str = zval_get_string(val);
php_http_arrkey_t arrkey = {0};
php_http_arrkey_stringify(&arrkey, &key);
append_encoded(&buf, arrkey.key->val, arrkey.key->len, str->val, str->len);
php_http_arrkey_dtor(&arrkey);
zend_string_release(str);
}
ZEND_HASH_FOREACH_END();
if (list->domain && *list->domain) {
php_http_buffer_appendf(&buf, "domain=%s; ", list->domain);
}
if (list->path && *list->path) {
php_http_buffer_appendf(&buf, "path=%s; ", list->path);
}
if (list->expires >= 0) {
zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), list->expires, 0);
php_http_buffer_appendf(&buf, "expires=%s; ", date->val);
zend_string_release(date);
}
if (list->max_age >= 0) {
php_http_buffer_appendf(&buf, "max-age=%ld; ", list->max_age);
}
ZEND_HASH_FOREACH_KEY_VAL(&list->extras, key.h, key.key, val)
{
zend_string *str = zval_get_string(val);
php_http_arrkey_t arrkey;
php_http_arrkey_stringify(&arrkey, &key);
append_encoded(&buf, arrkey.key->val, arrkey.key->len, str->val, str->len);
php_http_arrkey_dtor(&arrkey);
zend_string_release(str);
}
ZEND_HASH_FOREACH_END();
if (list->flags & PHP_HTTP_COOKIE_SECURE) {
php_http_buffer_appends(&buf, "secure; ");
}
if (list->flags & PHP_HTTP_COOKIE_HTTPONLY) {
php_http_buffer_appends(&buf, "httpOnly; ");
}
php_http_buffer_fix(&buf);
*str = buf.data;
*len = buf.used;
}
static zend_class_entry *php_http_cookie_class_entry;
zend_class_entry *php_http_cookie_get_class_entry(void)
{
return php_http_cookie_class_entry;
}
static zend_object_handlers php_http_cookie_object_handlers;
zend_object *php_http_cookie_object_new(zend_class_entry *ce)
{
return &php_http_cookie_object_new_ex(ce, NULL)->zo;
}
php_http_cookie_object_t *php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list)
{
php_http_cookie_object_t *o;
if (!ce) {
ce = php_http_cookie_class_entry;
}
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
o->zo.handlers = &php_http_cookie_object_handlers;
if (list) {
o->list = list;
}
return o;
}
#define PHP_HTTP_COOKIE_OBJECT_INIT(obj) \
do { \
if (!obj->list) { \
obj->list = php_http_cookie_list_init(NULL); \
} \
} while(0)
zend_object *php_http_cookie_object_clone(zval *obj)
{
php_http_cookie_object_t *new_obj, *old_obj = PHP_HTTP_OBJ(NULL, obj);
PHP_HTTP_COOKIE_OBJECT_INIT(old_obj);
new_obj = php_http_cookie_object_new_ex(old_obj->zo.ce, php_http_cookie_list_copy(old_obj->list, NULL));
zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
return &new_obj->zo;
}
void php_http_cookie_object_free(zend_object *object)
{
php_http_cookie_object_t *obj = PHP_HTTP_OBJ(object, NULL);
php_http_cookie_list_free(&obj->list);
zend_object_std_dtor(object);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie___construct, 0, 0, 0)
ZEND_ARG_INFO(0, cookie_string)
ZEND_ARG_INFO(0, parser_flags)
ZEND_ARG_INFO(0, allowed_extras)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, __construct)
{
php_http_cookie_object_t *obj;
zval *zcookie = NULL;
zend_long flags = 0;
char **ae = NULL;
HashTable *allowed_extras = NULL;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!lH", &zcookie, &flags, &allowed_extras), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh);
if (zcookie) {
if (allowed_extras && zend_hash_num_elements(allowed_extras)) {
char **ae_ptr = safe_emalloc(zend_hash_num_elements(allowed_extras) + 1, sizeof(char *), 0);
zval *val;
ae = ae_ptr;
ZEND_HASH_FOREACH_VAL(allowed_extras, val)
{
zend_string *str = zval_get_string(val);
*ae_ptr++ = estrndup(str->val, str->len);
zend_string_release(str);
}
ZEND_HASH_FOREACH_END();
*ae_ptr = NULL;
}
switch (Z_TYPE_P(zcookie)) {
case IS_OBJECT:
if (instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_class_entry)) {
php_http_cookie_object_t *zco = PHP_HTTP_OBJ(NULL, zcookie);
if (zco->list) {
obj->list = php_http_cookie_list_copy(zco->list, NULL);
}
break;
}
/* no break */
case IS_ARRAY:
obj->list = php_http_cookie_list_from_struct(obj->list, zcookie);
break;
default: {
zend_string *str = zval_get_string(zcookie);
obj->list = php_http_cookie_list_parse(obj->list, str->val, str->len, flags, ae);
zend_string_release(str);
break;
}
}
if (ae) {
char **ae_ptr;
for (ae_ptr = ae; *ae_ptr; ++ae_ptr) {
efree(*ae_ptr);
}
efree(ae);
}
}
zend_restore_error_handling(&zeh);
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookies, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, getCookies)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
array_init_size(return_value, zend_hash_num_elements(&obj->list->cookies));
array_copy(&obj->list->cookies, Z_ARRVAL_P(return_value));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookies, 0, 0, 0)
ZEND_ARG_INFO(0, cookies)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setCookies)
{
HashTable *cookies = NULL;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &cookies), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
zend_hash_clean(&obj->list->cookies);
if (cookies) {
array_copy_strings(cookies, &obj->list->cookies);
}
RETURN_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookies, 0, 0, 1)
ZEND_ARG_INFO(0, cookies)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, addCookies)
{
HashTable *cookies = NULL;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "H", &cookies), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
array_join(cookies, &obj->list->cookies, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtras, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, getExtras)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
array_init_size(return_value, zend_hash_num_elements(&obj->list->extras));
array_copy(&obj->list->extras, Z_ARRVAL_P(return_value));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtras, 0, 0, 0)
ZEND_ARG_INFO(0, extras)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setExtras)
{
HashTable *extras = NULL;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &extras), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
zend_hash_clean(&obj->list->extras);
if (extras) {
array_copy_strings(extras, &obj->list->extras);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtras, 0, 0, 1)
ZEND_ARG_INFO(0, extras)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, addExtras)
{
HashTable *extras = NULL;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "H", &extras), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
array_join(extras, &obj->list->extras, 1, ARRAY_JOIN_STRONLY|ARRAY_JOIN_STRINGIFY);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getCookie, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, getCookie)
{
char *name_str;
size_t name_len;
zval zvalue;
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len)) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (php_http_cookie_list_get_cookie(obj->list, name_str, name_len, &zvalue)) {
RETURN_ZVAL(&zvalue, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setCookie, 0, 0, 1)
ZEND_ARG_INFO(0, cookie_name)
ZEND_ARG_INFO(0, cookie_value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setCookie)
{
char *name_str, *value_str = NULL;
size_t name_len, value_len = 0;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (!value_str) {
php_http_cookie_list_del_cookie(obj->list, name_str, name_len);
} else {
php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addCookie, 0, 0, 2)
ZEND_ARG_INFO(0, cookie_name)
ZEND_ARG_INFO(0, cookie_value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, addCookie)
{
char *name_str, *value_str;
size_t name_len, value_len;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
php_http_cookie_list_add_cookie(obj->list, name_str, name_len, value_str, value_len);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExtra, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, getExtra)
{
char *name_str;
size_t name_len;
zval zvalue;
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s", &name_str, &name_len)) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (php_http_cookie_list_get_extra(obj->list, name_str, name_len, &zvalue)) {
RETURN_ZVAL(&zvalue, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExtra, 0, 0, 1)
ZEND_ARG_INFO(0, extra_name)
ZEND_ARG_INFO(0, extra_value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setExtra)
{
char *name_str, *value_str = NULL;
size_t name_len, value_len = 0;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (!value_str) {
php_http_cookie_list_del_extra(obj->list, name_str, name_len);
} else {
php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_addExtra, 0, 0, 2)
ZEND_ARG_INFO(0, extra_name)
ZEND_ARG_INFO(0, extra_value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, addExtra)
{
char *name_str, *value_str;
size_t name_len, value_len;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
php_http_cookie_list_add_extra(obj->list, name_str, name_len, value_str, value_len);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getDomain, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, getDomain)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (obj->list->domain) {
RETURN_STRING(obj->list->domain);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setDomain, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setDomain)
{
char *domain_str = NULL;
size_t domain_len = 0;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &domain_str, &domain_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
PTR_SET(obj->list->domain, domain_str ? estrndup(domain_str, domain_len) : NULL);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getPath, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, getPath)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
if (obj->list->path) {
RETURN_STRING(obj->list->path);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setPath, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setPath)
{
char *path_str = NULL;
size_t path_len = 0;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &path_str, &path_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
PTR_SET(obj->list->path, path_str ? estrndup(path_str, path_len) : NULL);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getExpires, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, getExpires)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
RETURN_LONG(obj->list->expires);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setExpires, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setExpires)
{
zend_long ts = -1;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &ts), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
obj->list->expires = ts;
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getMaxAge, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, getMaxAge)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
RETURN_LONG(obj->list->max_age);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setMaxAge, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setMaxAge)
{
zend_long ma = -1;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &ma), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
obj->list->max_age = ma;
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_getFlags, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, getFlags)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
RETURN_LONG(obj->list->flags);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_setFlags, 0, 0, 0)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpCookie, setFlags)
{
zend_long flags = 0;
php_http_cookie_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
obj->list->flags = flags;
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toString, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, toString)
{
php_http_cookie_object_t *obj;
char *str;
size_t len;
if (SUCCESS != zend_parse_parameters_none()) {
RETURN_EMPTY_STRING();
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
php_http_cookie_list_to_string(obj->list, &str, &len);
RETURN_NEW_STR(php_http_cs2zs(str, len));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpCookie_toArray, 0, 0, 0)
ZEND_END_ARG_INFO();;
static PHP_METHOD(HttpCookie, toArray)
{
php_http_cookie_object_t *obj;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_COOKIE_OBJECT_INIT(obj);
array_init_size(return_value, 8);
php_http_cookie_list_to_struct(obj->list, return_value);
}
static zend_function_entry php_http_cookie_methods[] = {
PHP_ME(HttpCookie, __construct, ai_HttpCookie___construct, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getCookies, ai_HttpCookie_getCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setCookies, ai_HttpCookie_setCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, addCookies, ai_HttpCookie_addCookies, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getCookie, ai_HttpCookie_getCookie, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setCookie, ai_HttpCookie_setCookie, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, addCookie, ai_HttpCookie_addCookie, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getExtras, ai_HttpCookie_getExtras, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setExtras, ai_HttpCookie_setExtras, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, addExtras, ai_HttpCookie_addExtras, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getExtra, ai_HttpCookie_getExtra, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setExtra, ai_HttpCookie_setExtra, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, addExtra, ai_HttpCookie_addExtra, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getDomain, ai_HttpCookie_getDomain, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setDomain, ai_HttpCookie_setDomain, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getPath, ai_HttpCookie_getPath, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setPath, ai_HttpCookie_setPath, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getExpires, ai_HttpCookie_getExpires, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setExpires, ai_HttpCookie_setExpires, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getMaxAge, ai_HttpCookie_getMaxAge, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setMaxAge, ai_HttpCookie_setMaxAge, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, getFlags, ai_HttpCookie_getFlags, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, setFlags, ai_HttpCookie_setFlags, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, toArray, ai_HttpCookie_toArray, ZEND_ACC_PUBLIC)
PHP_ME(HttpCookie, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpCookie, __toString, toString, ai_HttpCookie_toString, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_cookie)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Cookie", php_http_cookie_methods);
php_http_cookie_class_entry = zend_register_internal_class(&ce);
php_http_cookie_class_entry->create_object = php_http_cookie_object_new;
memcpy(&php_http_cookie_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_cookie_object_handlers.offset = XtOffsetOf(php_http_cookie_object_t, zo);
php_http_cookie_object_handlers.clone_obj = php_http_cookie_object_clone;
php_http_cookie_object_handlers.free_obj = php_http_cookie_object_free;
zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_COOKIE_PARSE_RAW);
zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("SECURE"), PHP_HTTP_COOKIE_SECURE);
zend_declare_class_constant_long(php_http_cookie_class_entry, ZEND_STRL("HTTPONLY"), PHP_HTTP_COOKIE_HTTPONLY);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_cookie.h 0000644 0001750 0000144 00000007407 12667772426 016513 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_COOKIE_H
#define PHP_HTTP_COOKIE_H
#define PHP_HTTP_COOKIE_SECURE 0x10L
#define PHP_HTTP_COOKIE_HTTPONLY 0x20L
#define PHP_HTTP_COOKIE_PARSE_RAW 0x01L
/*
generally a netscape cookie compliant struct, recognizing httpOnly attribute, too;
cookie params like those from rfc2109 and rfc2965 are just put into extras, if
one specifies them in allowed extras, else they're treated like cookies themself
*/
typedef struct php_http_cookie_list {
HashTable cookies;
HashTable extras;
long flags;
char *path;
char *domain;
time_t expires;
time_t max_age;
} php_http_cookie_list_t;
PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_list_t *list);
PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_list_t *list, const char *str, size_t len, long flags, char **allowed_extras);
PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_copy(php_http_cookie_list_t *from, php_http_cookie_list_t *to);
PHP_HTTP_API void php_http_cookie_list_dtor(php_http_cookie_list_t *list);
PHP_HTTP_API void php_http_cookie_list_free(php_http_cookie_list_t **list);
#define php_http_cookie_list_has_cookie(list, name, name_len) zend_symtable_str_exists(&(list)->cookies, (name), (name_len))
#define php_http_cookie_list_del_cookie(list, name, name_len) zend_symtable_str_del(&(list)->cookies, (name), (name_len))
PHP_HTTP_API void php_http_cookie_list_add_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len);
PHP_HTTP_API const char *php_http_cookie_list_get_cookie(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *cookie);
#define php_http_cookie_list_has_extra(list, name, name_len) zend_symtable_str_exists(&(list)->extras, (name), (name_len))
#define php_http_cookie_list_del_extra(list, name, name_len) zend_symtable_str_del(&(list)->extras, (name), (name_len))
PHP_HTTP_API void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, const char *value, size_t value_len);
PHP_HTTP_API const char *php_http_cookie_list_get_extra(php_http_cookie_list_t *list, const char *name, size_t name_len, zval *extra);
PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, char **str, size_t *len);
PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_cookie_list_t *list, zval *strct);
PHP_HTTP_API void php_http_cookie_list_to_struct(php_http_cookie_list_t *list, zval *strct);
PHP_HTTP_API zend_class_entry *php_http_cookie_get_class_entry(void);
typedef struct php_http_cookie_object {
php_http_cookie_list_t *list;
zend_object zo;
} php_http_cookie_object_t;
zend_object *php_http_cookie_object_new(zend_class_entry *ce);
php_http_cookie_object_t *php_http_cookie_object_new_ex(zend_class_entry *ce, php_http_cookie_list_t *list);
zend_object *php_http_cookie_object_clone(zval *this_ptr);
void php_http_cookie_object_free(zend_object *object);
PHP_MINIT_FUNCTION(http_cookie);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_curl.c 0000644 0001750 0000144 00000006737 12667772426 016207 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#if PHP_HTTP_HAVE_CURL
#if defined(ZTS) && defined(PHP_HTTP_HAVE_SSL)
# ifdef PHP_WIN32
# define PHP_HTTP_NEED_OPENSSL_TSL
# include
# else /* !PHP_WIN32 */
# if defined(PHP_HTTP_HAVE_OPENSSL)
# define PHP_HTTP_NEED_OPENSSL_TSL
# include
# elif defined(PHP_HTTP_HAVE_GNUTLS)
# define PHP_HTTP_NEED_GNUTLS_TSL
# include
# endif /* PHP_HTTP_HAVE_OPENSSL || PHP_HTTP_HAVE_GNUTLS */
# endif /* PHP_WIN32 */
#endif /* ZTS && PHP_HTTP_HAVE_SSL */
#ifdef PHP_HTTP_NEED_OPENSSL_TSL
static MUTEX_T *php_http_openssl_tsl = NULL;
static void php_http_openssl_thread_lock(int mode, int n, const char * file, int line)
{
if (mode & CRYPTO_LOCK) {
tsrm_mutex_lock(php_http_openssl_tsl[n]);
} else {
tsrm_mutex_unlock(php_http_openssl_tsl[n]);
}
}
static ulong php_http_openssl_thread_id(void)
{
return (ulong) tsrm_thread_id();
}
#endif
#ifdef PHP_HTTP_NEED_GNUTLS_TSL
static int php_http_gnutls_mutex_create(void **m)
{
if (*((MUTEX_T *) m) = tsrm_mutex_alloc()) {
return SUCCESS;
} else {
return FAILURE;
}
}
static int php_http_gnutls_mutex_destroy(void **m)
{
tsrm_mutex_free(*((MUTEX_T *) m));
return SUCCESS;
}
static int php_http_gnutls_mutex_lock(void **m)
{
return tsrm_mutex_lock(*((MUTEX_T *) m));
}
static int php_http_gnutls_mutex_unlock(void **m)
{
return tsrm_mutex_unlock(*((MUTEX_T *) m));
}
static struct gcry_thread_cbs php_http_gnutls_tsl = {
GCRY_THREAD_OPTION_USER,
NULL,
php_http_gnutls_mutex_create,
php_http_gnutls_mutex_destroy,
php_http_gnutls_mutex_lock,
php_http_gnutls_mutex_unlock
};
#endif
PHP_MINIT_FUNCTION(http_curl)
{
#ifdef PHP_HTTP_NEED_OPENSSL_TSL
/* mod_ssl, libpq or ext/curl might already have set thread lock callbacks */
if (!CRYPTO_get_id_callback()) {
int i, c = CRYPTO_num_locks();
php_http_openssl_tsl = malloc(c * sizeof(MUTEX_T));
for (i = 0; i < c; ++i) {
php_http_openssl_tsl[i] = tsrm_mutex_alloc();
}
CRYPTO_set_id_callback(php_http_openssl_thread_id);
CRYPTO_set_locking_callback(php_http_openssl_thread_lock);
}
#endif
#ifdef PHP_HTTP_NEED_GNUTLS_TSL
gcry_control(GCRYCTL_SET_THREAD_CBS, &php_http_gnutls_tsl);
#endif
if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) {
return FAILURE;
}
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(http_curl)
{
curl_global_cleanup();
#ifdef PHP_HTTP_NEED_OPENSSL_TSL
if (php_http_openssl_tsl) {
int i, c = CRYPTO_num_locks();
CRYPTO_set_id_callback(NULL);
CRYPTO_set_locking_callback(NULL);
for (i = 0; i < c; ++i) {
tsrm_mutex_free(php_http_openssl_tsl[i]);
}
free(php_http_openssl_tsl);
php_http_openssl_tsl = NULL;
}
#endif
return SUCCESS;
}
#endif /* PHP_HTTP_HAVE_CURL */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_curl.h 0000644 0001750 0000144 00000002163 12667772426 016201 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_CURL_H
#define PHP_HTTP_CURL_H
#if PHP_HTTP_HAVE_CURL
#include
#define PHP_HTTP_CURL_VERSION(x, y, z) (LIBCURL_VERSION_NUM >= (((x)<<16) + ((y)<<8) + (z)))
PHP_MINIT_FUNCTION(http_curl);
PHP_MSHUTDOWN_FUNCTION(http_curl);
#endif /* PHP_HTTP_HAVE_CURL */
#endif /* PHP_HTTP_CURL_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_encoding.c 0000644 0001750 0000144 00000110620 12667772426 017013 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
static inline int eol_match(char **line, int *eol_len)
{
char *ptr = *line;
while (' ' == *ptr) ++ptr;
if (ptr == php_http_locate_eol(*line, eol_len)) {
*line = ptr;
return 1;
} else {
return 0;
}
}
const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len)
{
int eol_len = 0;
char *n_ptr = NULL;
const char *e_ptr = encoded;
*decoded_len = 0;
*decoded = ecalloc(1, encoded_len + 1);
while ((encoded + encoded_len - e_ptr) > 0) {
ulong chunk_len = 0, rest;
chunk_len = strtoul(e_ptr, &n_ptr, 16);
/* we could not read in chunk size */
if (n_ptr == e_ptr) {
/*
* if this is the first turn and there doesn't seem to be a chunk
* size at the begining of the body, do not fail on apparently
* not encoded data and return a copy
*/
if (e_ptr == encoded) {
php_error_docref(NULL, E_NOTICE, "Data does not seem to be chunked encoded");
memcpy(*decoded, encoded, encoded_len);
*decoded_len = encoded_len;
return encoded + encoded_len;
} else {
efree(*decoded);
php_error_docref(NULL, E_WARNING, "Expected chunk size at pos %tu of %zu but got trash", n_ptr - encoded, encoded_len);
return NULL;
}
}
/* reached the end */
if (!chunk_len) {
/* move over '0' chunked encoding terminator and any new lines */
do {
switch (*e_ptr) {
case '0':
case '\r':
case '\n':
++e_ptr;
continue;
}
} while (0);
break;
}
/* there should be CRLF after the chunk size, but we'll ignore SP+ too */
if (*n_ptr && !eol_match(&n_ptr, &eol_len)) {
if (eol_len == 2) {
php_error_docref(NULL, E_WARNING, "Expected CRLF at pos %tu of %zu but got 0x%02X 0x%02X", n_ptr - encoded, encoded_len, *n_ptr, *(n_ptr + 1));
} else {
php_error_docref(NULL, E_WARNING, "Expected LF at pos %tu of %zu but got 0x%02X", n_ptr - encoded, encoded_len, *n_ptr);
}
}
n_ptr += eol_len;
/* chunk size pretends more data than we actually got, so it's probably a truncated message */
if (chunk_len > (rest = encoded + encoded_len - n_ptr)) {
php_error_docref(NULL, E_WARNING, "Truncated message: chunk size %lu exceeds remaining data size %lu at pos %tu of %zu", chunk_len, rest, n_ptr - encoded, encoded_len);
chunk_len = rest;
}
/* copy the chunk */
memcpy(*decoded + *decoded_len, n_ptr, chunk_len);
*decoded_len += chunk_len;
if (chunk_len == rest) {
e_ptr = n_ptr + chunk_len;
break;
} else {
/* advance to next chunk */
e_ptr = n_ptr + chunk_len + eol_len;
}
}
return e_ptr;
}
static inline int php_http_inflate_rounds(z_stream *Z, int flush, char **buf, size_t *len)
{
int status = 0, round = 0;
php_http_buffer_t buffer;
*buf = NULL;
*len = 0;
php_http_buffer_init_ex(&buffer, Z->avail_in, PHP_HTTP_BUFFER_INIT_PREALLOC);
do {
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_resize_ex(&buffer, buffer.size, 0, 1)) {
status = Z_MEM_ERROR;
} else {
Z->avail_out = buffer.free;
Z->next_out = (Bytef *) buffer.data + buffer.used;
#if 0
fprintf(stderr, "\n%3d: %3d PRIOR: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
#endif
status = inflate(Z, flush);
php_http_buffer_account(&buffer, buffer.free - Z->avail_out);
#if 0
fprintf(stderr, "%3d: %3d AFTER: size=%7lu,\tfree=%7lu,\tused=%7lu,\tavail_in=%7lu,\tavail_out=%7lu\n", round, status, buffer.size, buffer.free, buffer.used, Z->avail_in, Z->avail_out);
#endif
PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(buffer.size);
}
} while ((Z_BUF_ERROR == status || (Z_OK == status && Z->avail_in)) && ++round < PHP_HTTP_INFLATE_ROUNDS);
if (status == Z_OK || status == Z_STREAM_END) {
php_http_buffer_shrink(&buffer);
php_http_buffer_fix(&buffer);
*buf = buffer.data;
*len = buffer.used;
} else {
php_http_buffer_dtor(&buffer);
}
return status;
}
ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
{
int status, level, wbits, strategy;
z_stream Z;
PHP_HTTP_DEFLATE_LEVEL_SET(flags, level);
PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits);
PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy);
memset(&Z, 0, sizeof(z_stream));
*encoded = NULL;
*encoded_len = 0;
status = deflateInit2(&Z, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy);
if (Z_OK == status) {
*encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
*encoded = emalloc(*encoded_len);
Z.next_in = (Bytef *) data;
Z.next_out = (Bytef *) *encoded;
Z.avail_in = data_len;
Z.avail_out = *encoded_len;
status = deflate(&Z, Z_FINISH);
deflateEnd(&Z);
if (Z_STREAM_END == status) {
/* size buffer down to actual length */
*encoded = erealloc(*encoded, Z.total_out + 1);
(*encoded)[*encoded_len = Z.total_out] = '\0';
return SUCCESS;
} else {
PTR_SET(*encoded, NULL);
*encoded_len = 0;
}
}
php_error_docref(NULL, E_WARNING, "Could not deflate data: %s", zError(status));
return FAILURE;
}
ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len)
{
z_stream Z;
int status, wbits = PHP_HTTP_WINDOW_BITS_ANY;
memset(&Z, 0, sizeof(z_stream));
retry_raw_inflate:
status = inflateInit2(&Z, wbits);
if (Z_OK == status) {
Z.next_in = (Bytef *) data;
Z.avail_in = data_len + 1; /* include the terminating NULL, see #61287 */
switch (status = php_http_inflate_rounds(&Z, Z_NO_FLUSH, decoded, decoded_len)) {
case Z_STREAM_END:
inflateEnd(&Z);
return SUCCESS;
case Z_OK:
status = Z_DATA_ERROR;
break;
case Z_DATA_ERROR:
/* raw deflated data? */
if (PHP_HTTP_WINDOW_BITS_ANY == wbits) {
inflateEnd(&Z);
wbits = PHP_HTTP_WINDOW_BITS_RAW;
goto retry_raw_inflate;
}
break;
}
inflateEnd(&Z);
if (decoded_len && *decoded) {
efree(*decoded);
}
}
php_error_docref(NULL, E_WARNING, "Could not inflate data: %s", zError(status));
return FAILURE;
}
php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags)
{
int freeme;
if ((freeme = !s)) {
s = pemalloc(sizeof(*s), (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
}
memset(s, 0, sizeof(*s));
s->flags = flags;
if ((s->ops = ops)) {
php_http_encoding_stream_t *ss = s->ops->init(s);
if (ss) {
return ss;
}
} else {
return s;
}
if (freeme) {
pefree(s, (flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
}
return NULL;
}
php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
{
if (from->ops->copy) {
int freeme;
php_http_encoding_stream_t *ns;
if ((freeme = !to)) {
to = pemalloc(sizeof(*to), (from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
}
memset(to, 0, sizeof(*to));
to->flags = from->flags;
to->ops = from->ops;
if ((ns = to->ops->copy(from, to))) {
return ns;
} else {
return to;
}
if (freeme) {
pefree(to, (to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
}
}
return NULL;
}
ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s)
{
php_http_encoding_stream_t *ss;
if ((*s)->ops->dtor) {
(*s)->ops->dtor(*s);
}
if ((ss = (*s)->ops->init(*s))) {
*s = ss;
return SUCCESS;
}
return FAILURE;
}
ZEND_RESULT_CODE php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len)
{
if (!s->ops->update) {
return FAILURE;
}
return s->ops->update(s, in_str, in_len, out_str, out_len);
}
ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
{
if (!s->ops->flush) {
*out_str = NULL;
*out_len = 0;
return SUCCESS;
}
return s->ops->flush(s, out_str, out_len);
}
zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s)
{
if (!s->ops->done) {
return 0;
}
return s->ops->done(s);
}
ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *out_len)
{
if (!s->ops->finish) {
*out_str = NULL;
*out_len = 0;
return SUCCESS;
}
return s->ops->finish(s, out_str, out_len);
}
void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s)
{
if (s->ops->dtor) {
s->ops->dtor(s);
}
}
void php_http_encoding_stream_free(php_http_encoding_stream_t **s)
{
if (*s) {
if ((*s)->ops->dtor) {
(*s)->ops->dtor(*s);
}
pefree(*s, ((*s)->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
*s = NULL;
}
}
struct dechunk_ctx {
php_http_buffer_t buffer;
ulong hexlen;
unsigned zeroed:1;
};
static php_http_encoding_stream_t *deflate_init(php_http_encoding_stream_t *s)
{
int status, level, wbits, strategy, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
PHP_HTTP_DEFLATE_LEVEL_SET(s->flags, level);
PHP_HTTP_DEFLATE_WBITS_SET(s->flags, wbits);
PHP_HTTP_DEFLATE_STRATEGY_SET(s->flags, strategy);
if (Z_OK == (status = deflateInit2(ctx, level, Z_DEFLATED, wbits, MAX_MEM_LEVEL, strategy))) {
if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
s->ctx = ctx;
return s;
}
deflateEnd(ctx);
status = Z_MEM_ERROR;
}
pefree(ctx, p);
php_error_docref(NULL, E_WARNING, "Failed to initialize deflate encoding stream: %s", zError(status));
return NULL;
}
static php_http_encoding_stream_t *inflate_init(php_http_encoding_stream_t *s)
{
int status, wbits, p = (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT);
z_streamp ctx = pecalloc(1, sizeof(z_stream), p);
PHP_HTTP_INFLATE_WBITS_SET(s->flags, wbits);
if (Z_OK == (status = inflateInit2(ctx, wbits))) {
if ((ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
s->ctx = ctx;
return s;
}
inflateEnd(ctx);
status = Z_MEM_ERROR;
}
pefree(ctx, p);
php_error_docref(NULL, E_WARNING, "Failed to initialize inflate stream: %s", zError(status));
return NULL;
}
static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s)
{
struct dechunk_ctx *ctx = pecalloc(1, sizeof(*ctx), (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
if (!php_http_buffer_init_ex(&ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT) ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
return NULL;
}
ctx->hexlen = 0;
ctx->zeroed = 0;
s->ctx = ctx;
return s;
}
static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
{
int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
if (Z_OK == (status = deflateCopy(to_ctx, from_ctx))) {
if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
to->ctx = to_ctx;
return to;
}
deflateEnd(to_ctx);
status = Z_MEM_ERROR;
}
php_error_docref(NULL, E_WARNING, "Failed to copy deflate encoding stream: %s", zError(status));
return NULL;
}
static php_http_encoding_stream_t *inflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
{
int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p);
if (Z_OK == (status = inflateCopy(to_ctx, from_ctx))) {
if ((to_ctx->opaque = php_http_buffer_init_ex(NULL, PHP_HTTP_DEFLATE_BUFFER_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0))) {
php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER(from_ctx->opaque)->data, PHP_HTTP_BUFFER(from_ctx->opaque)->used);
to->ctx = to_ctx;
return to;
}
inflateEnd(to_ctx);
status = Z_MEM_ERROR;
}
php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: %s", zError(status));
return NULL;
}
static php_http_encoding_stream_t *dechunk_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to)
{
int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT;
struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p);
if (php_http_buffer_init_ex(&to_ctx->buffer, PHP_HTTP_BUFFER_DEFAULT_SIZE, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0)) {
to_ctx->hexlen = from_ctx->hexlen;
to_ctx->zeroed = from_ctx->zeroed;
php_http_buffer_append(&to_ctx->buffer, from_ctx->buffer.data, from_ctx->buffer.used);
to->ctx = to_ctx;
return to;
}
pefree(to_ctx, p);
php_error_docref(NULL, E_WARNING, "Failed to copy inflate encoding stream: out of memory");
return NULL;
}
static ZEND_RESULT_CODE deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len)
{
int status;
z_streamp ctx = s->ctx;
/* append input to our buffer */
php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
/* deflate */
*encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(data_len);
*encoded = emalloc(*encoded_len);
ctx->avail_out = *encoded_len;
ctx->next_out = (Bytef *) *encoded;
switch (status = deflate(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags))) {
case Z_OK:
case Z_STREAM_END:
/* cut processed chunk off the buffer */
if (ctx->avail_in) {
php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
} else {
php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
}
/* size buffer down to actual size */
*encoded_len -= ctx->avail_out;
*encoded = erealloc(*encoded, *encoded_len + 1);
(*encoded)[*encoded_len] = '\0';
return SUCCESS;
}
PTR_SET(*encoded, NULL);
*encoded_len = 0;
php_error_docref(NULL, E_WARNING, "Failed to update deflate stream: %s", zError(status));
return FAILURE;
}
static ZEND_RESULT_CODE inflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
{
int status;
z_streamp ctx = s->ctx;
/* append input to buffer */
php_http_buffer_append(PHP_HTTP_BUFFER(ctx->opaque), data, data_len);
retry_raw_inflate:
ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
switch (status = php_http_inflate_rounds(ctx, PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(s->flags), decoded, decoded_len)) {
case Z_OK:
case Z_STREAM_END:
/* cut off */
if (ctx->avail_in) {
php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
} else {
php_http_buffer_reset(PHP_HTTP_BUFFER(ctx->opaque));
}
return SUCCESS;
case Z_DATA_ERROR:
/* raw deflated data ? */
if (!(s->flags & PHP_HTTP_INFLATE_TYPE_RAW) && !ctx->total_out) {
inflateEnd(ctx);
s->flags |= PHP_HTTP_INFLATE_TYPE_RAW;
inflateInit2(ctx, PHP_HTTP_WINDOW_BITS_RAW);
goto retry_raw_inflate;
}
break;
}
php_error_docref(NULL, E_WARNING, "Failed to update inflate stream: %s", zError(status));
return FAILURE;
}
static ZEND_RESULT_CODE dechunk_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **decoded, size_t *decoded_len)
{
php_http_buffer_t tmp;
struct dechunk_ctx *ctx = s->ctx;
if (ctx->zeroed) {
php_error_docref(NULL, E_WARNING, "Dechunk encoding stream has already reached the end of chunked input");
return FAILURE;
}
if ((PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(&ctx->buffer, data, data_len)) || !php_http_buffer_fix(&ctx->buffer)) {
/* OOM */
return FAILURE;
}
*decoded = NULL;
*decoded_len = 0;
php_http_buffer_init(&tmp);
/* we have data in our buffer */
while (ctx->buffer.used) {
/* we already know the size of the chunk and are waiting for data */
if (ctx->hexlen) {
/* not enough data buffered */
if (ctx->buffer.used < ctx->hexlen) {
/* flush anyway? */
if (s->flags & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) {
/* flush all data (should only be chunk data) */
php_http_buffer_append(&tmp, ctx->buffer.data, ctx->buffer.used);
/* waiting for less data now */
ctx->hexlen -= ctx->buffer.used;
/* no more buffered data */
php_http_buffer_reset(&ctx->buffer);
/* break */
}
/* we have too less data and don't need to flush */
else {
break;
}
}
/* we seem to have all data of the chunk */
else {
php_http_buffer_append(&tmp, ctx->buffer.data, ctx->hexlen);
/* remove outgoing data from the buffer */
php_http_buffer_cut(&ctx->buffer, 0, ctx->hexlen);
/* reset hexlen */
ctx->hexlen = 0;
/* continue */
}
}
/* we don't know the length of the chunk yet */
else {
size_t off = 0;
/* ignore preceeding CRLFs (too loose?) */
while (off < ctx->buffer.used && (
ctx->buffer.data[off] == '\n' ||
ctx->buffer.data[off] == '\r')) {
++off;
}
if (off) {
php_http_buffer_cut(&ctx->buffer, 0, off);
}
/* still data there? */
if (ctx->buffer.used) {
int eollen;
const char *eolstr;
/* we need eol, so we can be sure we have all hex digits */
php_http_buffer_fix(&ctx->buffer);
if ((eolstr = php_http_locate_bin_eol(ctx->buffer.data, ctx->buffer.used, &eollen))) {
char *stop = NULL;
/* read in chunk size */
ctx->hexlen = strtoul(ctx->buffer.data, &stop, 16);
/* if strtoul() stops at the beginning of the buffered data
there's something oddly wrong, i.e. bad input */
if (stop == ctx->buffer.data) {
php_error_docref(NULL, E_WARNING, "Failed to parse chunk len from '%.*s'", (int) MIN(16, ctx->buffer.used), ctx->buffer.data);
php_http_buffer_dtor(&tmp);
return FAILURE;
}
/* cut out */
php_http_buffer_cut(&ctx->buffer, 0, eolstr + eollen - ctx->buffer.data);
/* buffer->hexlen is 0 now or contains the size of the next chunk */
if (!ctx->hexlen) {
size_t off = 0;
/* ignore following CRLFs (too loose?) */
while (off < ctx->buffer.used && (
ctx->buffer.data[off] == '\n' ||
ctx->buffer.data[off] == '\r')) {
++off;
}
if (off) {
php_http_buffer_cut(&ctx->buffer, 0, off);
}
ctx->zeroed = 1;
break;
}
/* continue */
} else {
/* we have not enough data buffered to read in chunk size */
break;
}
}
/* break */
}
}
php_http_buffer_fix(&tmp);
*decoded = tmp.data;
*decoded_len = tmp.used;
return SUCCESS;
}
static ZEND_RESULT_CODE deflate_flush(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
{
int status;
z_streamp ctx = s->ctx;
*encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
*encoded = emalloc(*encoded_len);
ctx->avail_in = 0;
ctx->next_in = NULL;
ctx->avail_out = *encoded_len;
ctx->next_out = (Bytef *) *encoded;
switch (status = deflate(ctx, Z_FULL_FLUSH)) {
case Z_OK:
case Z_STREAM_END:
*encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE - ctx->avail_out;
*encoded = erealloc(*encoded, *encoded_len + 1);
(*encoded)[*encoded_len] = '\0';
return SUCCESS;
}
PTR_SET(*encoded, NULL);
*encoded_len = 0;
php_error_docref(NULL, E_WARNING, "Failed to flush deflate stream: %s", zError(status));
return FAILURE;
}
static ZEND_RESULT_CODE dechunk_flush(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
{
struct dechunk_ctx *ctx = s->ctx;
if (ctx->hexlen) {
/* flush all data (should only be chunk data) */
php_http_buffer_fix(&ctx->buffer);
php_http_buffer_data(&ctx->buffer, decoded, decoded_len);
/* waiting for less data now */
ctx->hexlen -= ctx->buffer.used;
/* no more buffered data */
php_http_buffer_reset(&ctx->buffer);
} else {
*decoded = NULL;
*decoded_len = 0;
}
return SUCCESS;
}
static ZEND_RESULT_CODE deflate_finish(php_http_encoding_stream_t *s, char **encoded, size_t *encoded_len)
{
int status;
z_streamp ctx = s->ctx;
*encoded_len = PHP_HTTP_DEFLATE_BUFFER_SIZE;
*encoded = emalloc(*encoded_len);
/* deflate remaining input */
ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
ctx->avail_out = *encoded_len;
ctx->next_out = (Bytef *) *encoded;
do {
status = deflate(ctx, Z_FINISH);
} while (Z_OK == status);
if (Z_STREAM_END == status) {
/* cut processed input off */
php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
/* size down */
*encoded_len -= ctx->avail_out;
*encoded = erealloc(*encoded, *encoded_len + 1);
(*encoded)[*encoded_len] = '\0';
return SUCCESS;
}
PTR_SET(*encoded, NULL);
*encoded_len = 0;
php_error_docref(NULL, E_WARNING, "Failed to finish deflate stream: %s", zError(status));
return FAILURE;
}
static ZEND_RESULT_CODE inflate_finish(php_http_encoding_stream_t *s, char **decoded, size_t *decoded_len)
{
int status;
z_streamp ctx = s->ctx;
if (!PHP_HTTP_BUFFER(ctx->opaque)->used) {
*decoded = NULL;
*decoded_len = 0;
return SUCCESS;
}
*decoded_len = (PHP_HTTP_BUFFER(ctx->opaque)->used + 1) * PHP_HTTP_INFLATE_ROUNDS;
*decoded = emalloc(*decoded_len);
/* inflate remaining input */
ctx->next_in = (Bytef *) PHP_HTTP_BUFFER(ctx->opaque)->data;
ctx->avail_in = PHP_HTTP_BUFFER(ctx->opaque)->used;
ctx->avail_out = *decoded_len;
ctx->next_out = (Bytef *) *decoded;
if (Z_STREAM_END == (status = inflate(ctx, Z_FINISH))) {
/* cut processed input off */
php_http_buffer_cut(PHP_HTTP_BUFFER(ctx->opaque), 0, PHP_HTTP_BUFFER(ctx->opaque)->used - ctx->avail_in);
/* size down */
*decoded_len -= ctx->avail_out;
*decoded = erealloc(*decoded, *decoded_len + 1);
(*decoded)[*decoded_len] = '\0';
return SUCCESS;
}
PTR_SET(*decoded, NULL);
*decoded_len = 0;
php_error_docref(NULL, E_WARNING, "Failed to finish inflate stream: %s", zError(status));
return FAILURE;
}
static zend_bool deflate_done(php_http_encoding_stream_t *s)
{
z_streamp ctx = s->ctx;
return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
}
static zend_bool inflate_done(php_http_encoding_stream_t *s)
{
z_streamp ctx = s->ctx;
return !ctx->avail_in && !PHP_HTTP_BUFFER(ctx->opaque)->used;
}
static zend_bool dechunk_done(php_http_encoding_stream_t *s)
{
return ((struct dechunk_ctx *) s->ctx)->zeroed;
}
static void deflate_dtor(php_http_encoding_stream_t *s)
{
if (s->ctx) {
z_streamp ctx = s->ctx;
if (ctx->opaque) {
php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
}
deflateEnd(ctx);
pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
s->ctx = NULL;
}
}
static void inflate_dtor(php_http_encoding_stream_t *s)
{
if (s->ctx) {
z_streamp ctx = s->ctx;
if (ctx->opaque) {
php_http_buffer_free((php_http_buffer_t **) &ctx->opaque);
}
inflateEnd(ctx);
pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
s->ctx = NULL;
}
}
static void dechunk_dtor(php_http_encoding_stream_t *s)
{
if (s->ctx) {
struct dechunk_ctx *ctx = s->ctx;
php_http_buffer_dtor(&ctx->buffer);
pefree(ctx, (s->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT));
s->ctx = NULL;
}
}
static php_http_encoding_stream_ops_t php_http_encoding_deflate_ops = {
deflate_init,
deflate_copy,
deflate_update,
deflate_flush,
deflate_done,
deflate_finish,
deflate_dtor
};
php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void)
{
return &php_http_encoding_deflate_ops;
}
static php_http_encoding_stream_ops_t php_http_encoding_inflate_ops = {
inflate_init,
inflate_copy,
inflate_update,
NULL,
inflate_done,
inflate_finish,
inflate_dtor
};
php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void)
{
return &php_http_encoding_inflate_ops;
}
static php_http_encoding_stream_ops_t php_http_encoding_dechunk_ops = {
dechunk_init,
dechunk_copy,
dechunk_update,
dechunk_flush,
dechunk_done,
NULL,
dechunk_dtor
};
php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void)
{
return &php_http_encoding_dechunk_ops;
}
static zend_object_handlers php_http_encoding_stream_object_handlers;
zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce)
{
return &php_http_encoding_stream_object_new_ex(ce, NULL)->zo;
}
php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s)
{
php_http_encoding_stream_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
if (s) {
o->stream = s;
}
o->zo.handlers = &php_http_encoding_stream_object_handlers;
return o;
}
zend_object *php_http_encoding_stream_object_clone(zval *object)
{
php_http_encoding_stream_object_t *new_obj = NULL, *old_obj = PHP_HTTP_OBJ(NULL, object);
php_http_encoding_stream_t *cpy = php_http_encoding_stream_copy(old_obj->stream, NULL);
new_obj = php_http_encoding_stream_object_new_ex(old_obj->zo.ce, cpy);
zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
return &new_obj->zo;
}
void php_http_encoding_stream_object_free(zend_object *object)
{
php_http_encoding_stream_object_t *o = PHP_HTTP_OBJ(object, NULL);
if (o->stream) {
php_http_encoding_stream_free(&o->stream);
}
zend_object_std_dtor(object);
}
static zend_class_entry *php_http_encoding_stream_class_entry;
zend_class_entry *php_http_get_encoding_stream_class_entry(void)
{
return php_http_encoding_stream_class_entry;
}
static zend_class_entry *php_http_deflate_stream_class_entry;
zend_class_entry *php_http_get_deflate_stream_class_entry(void)
{
return php_http_deflate_stream_class_entry;
}
static zend_class_entry *php_http_inflate_stream_class_entry;
zend_class_entry *php_http_get_inflate_stream_class_entry(void)
{
return php_http_inflate_stream_class_entry;
}
static zend_class_entry *php_http_dechunk_stream_class_entry;
zend_class_entry *php_http_get_dechunk_stream_class_entry(void)
{
return php_http_dechunk_stream_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream___construct, 0, 0, 0)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEncodingStream, __construct)
{
zend_long flags = 0;
php_http_encoding_stream_object_t *obj;
php_http_encoding_stream_ops_t *ops;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &flags), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->stream) {
php_http_throw(bad_method_call, "http\\Encoding\\Stream cannot be initialized twice", NULL);
return;
}
if (instanceof_function(obj->zo.ce, php_http_deflate_stream_class_entry)) {
ops = &php_http_encoding_deflate_ops;
} else if (instanceof_function(obj->zo.ce, php_http_inflate_stream_class_entry)) {
ops = &php_http_encoding_inflate_ops;
} else if (instanceof_function(obj->zo.ce, php_http_dechunk_stream_class_entry)) {
ops = &php_http_encoding_dechunk_ops;
} else {
php_http_throw(runtime, "Unknown http\\Encoding\\Stream class '%s'", obj->zo.ce->name->val);
return;
}
php_http_expect(obj->stream = php_http_encoding_stream_init(obj->stream, ops, flags), runtime, return);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_update, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEncodingStream, update)
{
size_t data_len;
char *data_str;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &data_str, &data_len)) {
php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->stream) {
char *encoded_str = NULL;
size_t encoded_len;
if (SUCCESS == php_http_encoding_stream_update(obj->stream, data_str, data_len, &encoded_str, &encoded_len)) {
if (encoded_str) {
RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_flush, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEncodingStream, flush)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->stream) {
char *encoded_str = NULL;
size_t encoded_len;
if (SUCCESS == php_http_encoding_stream_flush(obj->stream, &encoded_str, &encoded_len)) {
if (encoded_str) {
RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_done, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEncodingStream, done)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->stream) {
RETURN_BOOL(php_http_encoding_stream_done(obj->stream));
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEncodingStream_finish, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEncodingStream, finish)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_encoding_stream_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (obj->stream) {
char *encoded_str = NULL;
size_t encoded_len;
if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len)) {
if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) {
if (encoded_str) {
RETURN_STR(php_http_cs2zs(encoded_str, encoded_len));
} else {
RETURN_EMPTY_STRING();
}
} else {
PTR_FREE(encoded_str);
}
}
}
}
}
static zend_function_entry php_http_encoding_stream_methods[] = {
PHP_ME(HttpEncodingStream, __construct, ai_HttpEncodingStream___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpEncodingStream, update, ai_HttpEncodingStream_update, ZEND_ACC_PUBLIC)
PHP_ME(HttpEncodingStream, flush, ai_HttpEncodingStream_flush, ZEND_ACC_PUBLIC)
PHP_ME(HttpEncodingStream, done, ai_HttpEncodingStream_done, ZEND_ACC_PUBLIC)
PHP_ME(HttpEncodingStream, finish, ai_HttpEncodingStream_finish, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
ZEND_BEGIN_ARG_INFO_EX(ai_HttpDeflateStream_encode, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpDeflateStream, encode)
{
char *str;
size_t len;
zend_long flags = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &len, &flags)) {
char *enc_str = NULL;
size_t enc_len;
if (SUCCESS == php_http_encoding_deflate(flags, str, len, &enc_str, &enc_len)) {
if (enc_str) {
RETURN_STR(php_http_cs2zs(enc_str, enc_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
RETURN_FALSE;
}
static zend_function_entry php_http_deflate_stream_methods[] = {
PHP_ME(HttpDeflateStream, encode, ai_HttpDeflateStream_encode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
EMPTY_FUNCTION_ENTRY
};
ZEND_BEGIN_ARG_INFO_EX(ai_HttpInflateStream_decode, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpInflateStream, decode)
{
char *str;
size_t len;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len)) {
char *enc_str = NULL;
size_t enc_len;
if (SUCCESS == php_http_encoding_inflate(str, len, &enc_str, &enc_len)) {
if (enc_str) {
RETURN_STR(php_http_cs2zs(enc_str, enc_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
RETURN_FALSE;
}
static zend_function_entry php_http_inflate_stream_methods[] = {
PHP_ME(HttpInflateStream, decode, ai_HttpInflateStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
EMPTY_FUNCTION_ENTRY
};
ZEND_BEGIN_ARG_INFO_EX(ai_HttpDechunkStream_decode, 0, 0, 1)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(1, decoded_len)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpDechunkStream, decode)
{
char *str;
size_t len;
zval *zlen = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &str, &len, &zlen)) {
const char *end_ptr;
char *enc_str = NULL;
size_t enc_len;
if ((end_ptr = php_http_encoding_dechunk(str, len, &enc_str, &enc_len))) {
if (zlen) {
ZVAL_DEREF(zlen);
zval_dtor(zlen);
ZVAL_LONG(zlen, str + len - end_ptr);
}
if (enc_str) {
RETURN_STR(php_http_cs2zs(enc_str, enc_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
RETURN_FALSE;
}
static zend_function_entry php_http_dechunk_stream_methods[] = {
PHP_ME(HttpDechunkStream, decode, ai_HttpDechunkStream_decode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_encoding)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Encoding", "Stream", php_http_encoding_stream_methods);
php_http_encoding_stream_class_entry = zend_register_internal_class(&ce);
php_http_encoding_stream_class_entry->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;
php_http_encoding_stream_class_entry->create_object = php_http_encoding_stream_object_new;
memcpy(&php_http_encoding_stream_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_encoding_stream_object_handlers.offset = XtOffsetOf(php_http_encoding_stream_object_t, zo);
php_http_encoding_stream_object_handlers.clone_obj = php_http_encoding_stream_object_clone;
php_http_encoding_stream_object_handlers.free_obj = php_http_encoding_stream_object_free;
zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_NONE"), PHP_HTTP_ENCODING_STREAM_FLUSH_NONE);
zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_SYNC"), PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC);
zend_declare_class_constant_long(php_http_encoding_stream_class_entry, ZEND_STRL("FLUSH_FULL"), PHP_HTTP_ENCODING_STREAM_FLUSH_FULL);
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Deflate", php_http_deflate_stream_methods);
php_http_deflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
php_http_deflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_GZIP"), PHP_HTTP_DEFLATE_TYPE_GZIP);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_ZLIB"), PHP_HTTP_DEFLATE_TYPE_ZLIB);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("TYPE_RAW"), PHP_HTTP_DEFLATE_TYPE_RAW);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_DEF"), PHP_HTTP_DEFLATE_LEVEL_DEF);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MIN"), PHP_HTTP_DEFLATE_LEVEL_MIN);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("LEVEL_MAX"), PHP_HTTP_DEFLATE_LEVEL_MAX);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_DEF"), PHP_HTTP_DEFLATE_STRATEGY_DEF);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FILT"), PHP_HTTP_DEFLATE_STRATEGY_FILT);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_HUFF"), PHP_HTTP_DEFLATE_STRATEGY_HUFF);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_RLE"), PHP_HTTP_DEFLATE_STRATEGY_RLE);
zend_declare_class_constant_long(php_http_deflate_stream_class_entry, ZEND_STRL("STRATEGY_FIXED"), PHP_HTTP_DEFLATE_STRATEGY_FIXED);
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Inflate", php_http_inflate_stream_methods);
php_http_inflate_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
php_http_inflate_stream_class_entry->create_object = php_http_encoding_stream_object_new;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Encoding\\Stream", "Dechunk", php_http_dechunk_stream_methods);
php_http_dechunk_stream_class_entry = zend_register_internal_class_ex(&ce, php_http_encoding_stream_class_entry);
php_http_dechunk_stream_class_entry->create_object = php_http_encoding_stream_object_new;
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_encoding.h 0000644 0001750 0000144 00000017411 12667772426 017024 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_ENCODING_H
#define PHP_HTTP_ENCODING_H
#include
extern PHP_MINIT_FUNCTION(http_encoding);
extern PHP_RINIT_FUNCTION(http_encoding);
extern PHP_RSHUTDOWN_FUNCTION(http_encoding);
#define PHP_HTTP_INFLATE_ROUNDS 100
#define PHP_HTTP_DEFLATE_BUFFER_SIZE_GUESS(S) \
(((size_t) ((double) S * (double) 1.015)) + 10 + 8 + 4 + 1)
#define PHP_HTTP_INFLATE_BUFFER_SIZE_GUESS(S) \
(((S) + 1) << 3)
#define PHP_HTTP_INFLATE_BUFFER_SIZE_ALIGN(S) \
((S) += (S) >> (3))
#define PHP_HTTP_DEFLATE_BUFFER_SIZE 0x8000
#define PHP_HTTP_INFLATE_BUFFER_SIZE 0x1000
#define PHP_HTTP_DEFLATE_LEVEL_DEF 0x00000000
#define PHP_HTTP_DEFLATE_LEVEL_MIN 0x00000001
#define PHP_HTTP_DEFLATE_LEVEL_MAX 0x00000009
#define PHP_HTTP_DEFLATE_TYPE_ZLIB 0x00000000
#define PHP_HTTP_DEFLATE_TYPE_GZIP 0x00000010
#define PHP_HTTP_DEFLATE_TYPE_RAW 0x00000020
#define PHP_HTTP_DEFLATE_STRATEGY_DEF 0x00000000
#define PHP_HTTP_DEFLATE_STRATEGY_FILT 0x00000100
#define PHP_HTTP_DEFLATE_STRATEGY_HUFF 0x00000200
#define PHP_HTTP_DEFLATE_STRATEGY_RLE 0x00000300
#define PHP_HTTP_DEFLATE_STRATEGY_FIXED 0x00000400
#define PHP_HTTP_DEFLATE_LEVEL_SET(flags, level) \
switch (flags & 0xf) \
{ \
default: \
if ((flags & 0xf) < 10) { \
level = flags & 0xf; \
break; \
} \
case PHP_HTTP_DEFLATE_LEVEL_DEF: \
level = Z_DEFAULT_COMPRESSION; \
break; \
}
#define PHP_HTTP_DEFLATE_WBITS_SET(flags, wbits) \
switch (flags & 0xf0) \
{ \
case PHP_HTTP_DEFLATE_TYPE_GZIP: \
wbits = PHP_HTTP_WINDOW_BITS_GZIP; \
break; \
case PHP_HTTP_DEFLATE_TYPE_RAW: \
wbits = PHP_HTTP_WINDOW_BITS_RAW; \
break; \
default: \
wbits = PHP_HTTP_WINDOW_BITS_ZLIB; \
break; \
}
#define PHP_HTTP_INFLATE_WBITS_SET(flags, wbits) \
if (flags & PHP_HTTP_INFLATE_TYPE_RAW) { \
wbits = PHP_HTTP_WINDOW_BITS_RAW; \
} else { \
wbits = PHP_HTTP_WINDOW_BITS_ANY; \
}
#define PHP_HTTP_DEFLATE_STRATEGY_SET(flags, strategy) \
switch (flags & 0xf00) \
{ \
case PHP_HTTP_DEFLATE_STRATEGY_FILT: \
strategy = Z_FILTERED; \
break; \
case PHP_HTTP_DEFLATE_STRATEGY_HUFF: \
strategy = Z_HUFFMAN_ONLY; \
break; \
case PHP_HTTP_DEFLATE_STRATEGY_RLE: \
strategy = Z_RLE; \
break; \
case PHP_HTTP_DEFLATE_STRATEGY_FIXED: \
strategy = Z_FIXED; \
break; \
default: \
strategy = Z_DEFAULT_STRATEGY; \
break; \
}
#define PHP_HTTP_WINDOW_BITS_ZLIB 0x0000000f
#define PHP_HTTP_WINDOW_BITS_GZIP 0x0000001f
#define PHP_HTTP_WINDOW_BITS_ANY 0x0000002f
#define PHP_HTTP_WINDOW_BITS_RAW -0x000000f
#ifndef Z_FIXED
/* Z_FIXED does not exist prior 1.2.2.2 */
# define Z_FIXED 0
#endif
#define PHP_HTTP_INFLATE_TYPE_ZLIB 0x00000000
#define PHP_HTTP_INFLATE_TYPE_GZIP 0x00000000
#define PHP_HTTP_INFLATE_TYPE_RAW 0x00000001
#define PHP_HTTP_ENCODING_STREAM_FLUSH_NONE 0x00000000
#define PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC 0x00100000
#define PHP_HTTP_ENCODING_STREAM_FLUSH_FULL 0x00200000
#define PHP_HTTP_ENCODING_STREAM_FLUSH_FLAG(f) \
(((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_FULL) ? Z_FULL_FLUSH : \
(((f) & PHP_HTTP_ENCODING_STREAM_FLUSH_SYNC) ? Z_SYNC_FLUSH : Z_NO_FLUSH))
#define PHP_HTTP_ENCODING_STREAM_PERSISTENT 0x01000000
typedef struct php_http_encoding_stream php_http_encoding_stream_t;
typedef php_http_encoding_stream_t *(*php_http_encoding_stream_init_func_t)(php_http_encoding_stream_t *s);
typedef php_http_encoding_stream_t *(*php_http_encoding_stream_copy_func_t)(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to);
typedef ZEND_RESULT_CODE (*php_http_encoding_stream_update_func_t)(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len);
typedef ZEND_RESULT_CODE (*php_http_encoding_stream_flush_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len);
typedef zend_bool (*php_http_encoding_stream_done_func_t)(php_http_encoding_stream_t *s);
typedef ZEND_RESULT_CODE (*php_http_encoding_stream_finish_func_t)(php_http_encoding_stream_t *s, char **out_str, size_t *out_len);
typedef void (*php_http_encoding_stream_dtor_func_t)(php_http_encoding_stream_t *s);
typedef struct php_http_encoding_stream_ops {
php_http_encoding_stream_init_func_t init;
php_http_encoding_stream_copy_func_t copy;
php_http_encoding_stream_update_func_t update;
php_http_encoding_stream_flush_func_t flush;
php_http_encoding_stream_done_func_t done;
php_http_encoding_stream_finish_func_t finish;
php_http_encoding_stream_dtor_func_t dtor;
} php_http_encoding_stream_ops_t;
struct php_http_encoding_stream {
unsigned flags;
void *ctx;
php_http_encoding_stream_ops_t *ops;
};
PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_deflate_ops(void);
PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_inflate_ops(void);
PHP_HTTP_API php_http_encoding_stream_ops_t *php_http_encoding_stream_get_dechunk_ops(void);
PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_init(php_http_encoding_stream_t *s, php_http_encoding_stream_ops_t *ops, unsigned flags);
PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_reset(php_http_encoding_stream_t **s);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_update(php_http_encoding_stream_t *s, const char *in_str, size_t in_len, char **out_str, size_t *out_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_flush(php_http_encoding_stream_t *s, char **out_str, size_t *len);
PHP_HTTP_API zend_bool php_http_encoding_stream_done(php_http_encoding_stream_t *s);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_stream_finish(php_http_encoding_stream_t *s, char **out_str, size_t *len);
PHP_HTTP_API void php_http_encoding_stream_dtor(php_http_encoding_stream_t *s);
PHP_HTTP_API void php_http_encoding_stream_free(php_http_encoding_stream_t **s);
PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t encoded_len, char **decoded, size_t *decoded_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_deflate(int flags, const char *data, size_t data_len, char **encoded, size_t *encoded_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_encoding_inflate(const char *data, size_t data_len, char **decoded, size_t *decoded_len);
typedef struct php_http_encoding_stream_object {
php_http_encoding_stream_t *stream;
zend_object zo;
} php_http_encoding_stream_object_t;
PHP_HTTP_API zend_class_entry *php_http_get_encoding_stream_class_entry(void);
zend_object *php_http_encoding_stream_object_new(zend_class_entry *ce);
php_http_encoding_stream_object_t *php_http_encoding_stream_object_new_ex(zend_class_entry *ce, php_http_encoding_stream_t *s);
zend_object *php_http_encoding_stream_object_clone(zval *object);
void php_http_encoding_stream_object_free(zend_object *object);
PHP_HTTP_API zend_class_entry *php_http_get_deflate_stream_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_inflate_stream_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_dechunk_stream_class_entry(void);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env.c 0000644 0001750 0000144 00000054152 12667772426 016024 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include "php_variables.h"
PHP_RSHUTDOWN_FUNCTION(http_env)
{
if (PHP_HTTP_G->env.request.headers) {
zend_hash_destroy(PHP_HTTP_G->env.request.headers);
FREE_HASHTABLE(PHP_HTTP_G->env.request.headers);
PHP_HTTP_G->env.request.headers = NULL;
}
if (PHP_HTTP_G->env.request.body) {
php_http_message_body_free(&PHP_HTTP_G->env.request.body);
}
if (PHP_HTTP_G->env.server_var) {
zval_ptr_dtor(PHP_HTTP_G->env.server_var);
PHP_HTTP_G->env.server_var = NULL;
}
return SUCCESS;
}
void php_http_env_get_request_headers(HashTable *headers)
{
php_http_arrkey_t key;
zval *hsv, *header;
if (!PHP_HTTP_G->env.request.headers) {
ALLOC_HASHTABLE(PHP_HTTP_G->env.request.headers);
ZEND_INIT_SYMTABLE(PHP_HTTP_G->env.request.headers);
if ((hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(hsv), key.h, key.key, header)
{
if (key.key && key.key->len > 5 && *key.key->val == 'H' && !strncmp(key.key->val, "HTTP_", 5)) {
size_t key_len = key.key->len - 5;
char *key_str = php_http_pretty_key(estrndup(&key.key->val[5], key_len), key_len, 1, 1);
Z_TRY_ADDREF_P(header);
zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key_len, header);
efree(key_str);
} else if (key.key && key.key->len > 8 && *key.key->val == 'C' && !strncmp(key.key->val, "CONTENT_", 8)) {
char *key_str = php_http_pretty_key(estrndup(key.key->val, key.key->len), key.key->len, 1, 1);
Z_TRY_ADDREF_P(header);
zend_symtable_str_update(PHP_HTTP_G->env.request.headers, key_str, key.key->len, header);
efree(key_str);
}
}
ZEND_HASH_FOREACH_END();
}
}
if (headers) {
array_copy(PHP_HTTP_G->env.request.headers, headers);
}
}
char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request)
{
HashTable *request_headers;
zval *zvalue = NULL;
char *val = NULL, *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
if (request) {
request_headers = &request->hdrs;
} else {
php_http_env_get_request_headers(NULL);
request_headers = PHP_HTTP_G->env.request.headers;
}
if ((zvalue = zend_symtable_str_find(request_headers, key, name_len))) {
zend_string *zs = zval_get_string(zvalue);
val = estrndup(zs->val, zs->len);
if (len) {
*len = zs->len;
}
zend_string_release(zs);
}
efree(key);
return val;
}
zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request)
{
HashTable *request_headers;
char *key = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
zend_bool got;
if (request) {
request_headers = &request->hdrs;
} else {
php_http_env_get_request_headers(NULL);
request_headers = PHP_HTTP_G->env.request.headers;
}
got = zend_symtable_str_exists(request_headers, key, name_len);
efree(key);
return got;
}
zval *php_http_env_get_superglobal(const char *key, size_t key_len)
{
zval *hsv;
zend_string *key_str = zend_string_init(key, key_len, 0);
zend_is_auto_global(key_str);
hsv = zend_hash_find(&EG(symbol_table), key_str);
zend_string_release(key_str);
if (Z_TYPE_P(hsv) != IS_ARRAY) {
return NULL;
}
return hsv;
}
zval *php_http_env_get_server_var(const char *key, size_t key_len, zend_bool check)
{
zval *hsv, *var;
/* if available, this is a lot faster than accessing $_SERVER * /
if (sapi_module.getenv) {
char *env;
if ((!(env = sapi_module.getenv((char *) key, key_len))) || (check && !*env)) {
return NULL;
}
if (PHP_HTTP_G->env.server_var) {
zval_ptr_dtor(&PHP_HTTP_G->env.server_var);
}
MAKE_STD_ZVAL(PHP_HTTP_G->env.server_var);
ZVAL_STRING(PHP_HTTP_G->env.server_var, env, 1);
return PHP_HTTP_G->env.server_var;
}
/ * */
if (!(hsv = php_http_env_get_superglobal(ZEND_STRL("_SERVER")))) {
return NULL;
}
if (!(var = zend_symtable_str_find(Z_ARRVAL_P(hsv), key, key_len))) {
return NULL;
}
if (check && !((Z_TYPE_P(var) == IS_STRING) && Z_STRVAL_P(var) && Z_STRLEN_P(var))) {
return NULL;
}
return var;
}
php_http_message_body_t *php_http_env_get_request_body(void)
{
if (!PHP_HTTP_G->env.request.body) {
php_stream *s = php_stream_temp_new();
php_stream *input = php_stream_open_wrapper("php://input", "r", 0, NULL);
/* php://input does not support stat */
php_stream_copy_to_stream_ex(input, s, -1, NULL);
php_stream_close(input);
php_stream_rewind(s);
PHP_HTTP_G->env.request.body = php_http_message_body_init(NULL, s);
}
return PHP_HTTP_G->env.request.body;
}
const char *php_http_env_get_request_method(php_http_message_t *request)
{
const char *m;
if (PHP_HTTP_MESSAGE_TYPE(REQUEST, request)) {
m = request->http.info.request.method;
} else {
m = SG(request_info).request_method;
}
return m ? m : "GET";
}
php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t length, php_http_message_t *request)
{
zval zentry;
char *range, *rp, c;
long begin = -1, end = -1, *ptr;
if (!(range = php_http_env_get_request_header(ZEND_STRL("Range"), NULL, request))) {
return PHP_HTTP_RANGE_NO;
}
if (strncmp(range, "bytes=", lenof("bytes="))) {
PTR_FREE(range);
return PHP_HTTP_RANGE_NO;
}
rp = range + lenof("bytes=");
ptr = &begin;
do {
switch (c = *(rp++)) {
case '0':
/* allow 000... - shall we? */
if (*ptr != -10) {
*ptr *= 10;
}
break;
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
/*
* If the value of the pointer is already set (non-negative)
* then multiply its value by ten and add the current value,
* else initialise the pointers value with the current value
* --
* This let us recognize empty fields when validating the
* ranges, i.e. a "-10" for begin and "12345" for the end
* was the following range request: "Range: bytes=0-12345";
* While a "-1" for begin and "12345" for the end would
* have been: "Range: bytes=-12345".
*/
if (*ptr > 0) {
*ptr *= 10;
*ptr += c - '0';
} else {
*ptr = c - '0';
}
break;
case '-':
ptr = &end;
break;
case ' ':
break;
case 0:
case ',':
if (length) {
/* validate ranges */
switch (begin) {
/* "0-12345" */
case -10:
switch (end) {
/* "0-" */
case -1:
PTR_FREE(range);
return PHP_HTTP_RANGE_NO;
/* "0-0" */
case -10:
end = 0;
break;
default:
if (length <= (size_t) end) {
end = length - 1;
}
break;
}
begin = 0;
break;
/* "-12345" */
case -1:
/* "-", "-0" */
if (end == -1 || end == -10) {
PTR_FREE(range);
return PHP_HTTP_RANGE_ERR;
}
begin = length - end;
end = length - 1;
break;
/* "12345-(NNN)" */
default:
if (length <= (size_t) begin) {
PTR_FREE(range);
return PHP_HTTP_RANGE_ERR;
}
switch (end) {
/* "12345-0" */
case -10:
PTR_FREE(range);
return PHP_HTTP_RANGE_ERR;
/* "12345-" */
case -1:
end = length - 1;
break;
/* "12345-67890" */
default:
if (length <= (size_t) end) {
end = length - 1;
} else if (end < begin) {
PTR_FREE(range);
return PHP_HTTP_RANGE_ERR;
}
break;
}
break;
}
}
array_init(&zentry);
add_index_long(&zentry, 0, begin);
add_index_long(&zentry, 1, end);
zend_hash_next_index_insert(ranges, &zentry);
begin = -1;
end = -1;
ptr = &begin;
break;
default:
PTR_FREE(range);
return PHP_HTTP_RANGE_NO;
}
} while (c != 0);
PTR_FREE(range);
return PHP_HTTP_RANGE_OK;
}
static void grab_headers(void *data, void *arg)
{
php_http_buffer_appendl(PHP_HTTP_BUFFER(arg), ((sapi_header_struct *)data)->header);
php_http_buffer_appends(PHP_HTTP_BUFFER(arg), PHP_HTTP_CRLF);
}
static void grab_header(void *data, void *arg)
{
struct {
char *name_str;
size_t name_len;
char *value_ptr;
} *args = arg;
sapi_header_struct *header = data;
if ( header->header_len > args->name_len
&& header->header[args->name_len] == ':'
&& !strncmp(header->header, args->name_str, args->name_len)
) {
args->value_ptr = &header->header[args->name_len + 1];
while (PHP_HTTP_IS_CTYPE(space, *args->value_ptr)) {
++args->value_ptr;
}
}
}
ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht)
{
ZEND_RESULT_CODE status;
php_http_buffer_t headers;
php_http_buffer_init(&headers);
zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_headers, &headers);
php_http_buffer_fix(&headers);
status = php_http_header_parse(headers.data, headers.used, headers_ht, NULL, NULL);
php_http_buffer_dtor(&headers);
return status;
}
char *php_http_env_get_response_header(const char *name_str, size_t name_len)
{
struct {
char *name_str;
size_t name_len;
char *value_ptr;
} args;
args.name_str = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
args.name_len = name_len;
args.value_ptr = NULL;
zend_llist_apply_with_argument(&SG(sapi_headers).headers, grab_header, &args);
efree(args.name_str);
return args.value_ptr ? estrdup(args.value_ptr) : NULL;
}
long php_http_env_get_response_code(void)
{
long code = SG(sapi_headers).http_response_code;
return code ? code : 200;
}
ZEND_RESULT_CODE php_http_env_set_response_code(long http_code)
{
return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (zend_intptr_t) http_code);
}
ZEND_RESULT_CODE php_http_env_set_response_status_line(long code, php_http_version_t *v)
{
sapi_header_line h = {NULL, 0, 0};
ZEND_RESULT_CODE ret;
h.line_len = spprintf(&h.line, 0, "HTTP/%u.%u %ld %s", v->major, v->minor, code, php_http_env_get_response_status_for_code(code));
ret = sapi_header_op(SAPI_HEADER_REPLACE, (void *) &h);
efree(h.line);
return ret;
}
ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v)
{
return php_http_env_set_response_status_line(php_http_env_get_response_code(), v);
}
ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace)
{
sapi_header_line h = {estrndup(header_str, header_len), header_len, http_code};
ZEND_RESULT_CODE ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
efree(h.line);
return ret;
}
ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv)
{
ZEND_RESULT_CODE ret = FAILURE;
sapi_header_line h = {NULL, 0, http_code};
h.line_len = vspprintf(&h.line, 0, fmt, argv);
if (h.line) {
if (h.line_len) {
ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
}
efree(h.line);
}
return ret;
}
ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...)
{
ZEND_RESULT_CODE ret;
va_list args;
va_start(args, fmt);
ret = php_http_env_set_response_header_va(http_code, replace, fmt, args);
va_end(args);
return ret;
}
ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace)
{
if (!value) {
sapi_header_line h = {(char *) name_str, name_len, http_code};
return sapi_header_op(SAPI_HEADER_DELETE, (void *) &h);
}
if (Z_TYPE_P(value) == IS_ARRAY || Z_TYPE_P(value) == IS_OBJECT) {
int first = replace;
zval *data_ptr;
HashTable *ht = HASH_OF(value);
ZEND_HASH_FOREACH_VAL_IND(ht, data_ptr)
{
if (SUCCESS != php_http_env_set_response_header_value(http_code, name_str, name_len, data_ptr, first)) {
return FAILURE;
}
first = 0;
}
ZEND_HASH_FOREACH_END();
return SUCCESS;
} else {
zend_string *data = zval_get_string(value);
if (!data->len) {
zend_string_release(data);
return php_http_env_set_response_header_value(http_code, name_str, name_len, NULL, replace);
} else {
sapi_header_line h;
ZEND_RESULT_CODE ret;
if (name_len > INT_MAX) {
return FAILURE;
}
h.response_code = http_code;
h.line_len = spprintf(&h.line, 0, "%.*s: %.*s", (int) name_len, name_str, data->len, data->val);
ret = sapi_header_op(replace ? SAPI_HEADER_REPLACE : SAPI_HEADER_ADD, (void *) &h);
zend_string_release(data);
PTR_FREE(h.line);
return ret;
}
}
}
const char *php_http_env_get_response_status_for_code(unsigned code)
{
switch (code) {
#define PHP_HTTP_RESPONSE_CODE(c, s) case c: return s;
#include "php_http_response_codes.h"
#undef PHP_HTTP_RESPONSE_CODE
default:
return NULL;
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestHeader, 0, 0, 0)
ZEND_ARG_INFO(0, header_name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getRequestHeader)
{
char *header_name_str = NULL;
size_t header_name_len = 0;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
return;
}
if (header_name_str && header_name_len) {
size_t header_length;
char *header_value = php_http_env_get_request_header(header_name_str, header_name_len, &header_length, NULL);
if (header_value) {
RETURN_STR(php_http_cs2zs(header_value, header_length));
}
} else {
array_init(return_value);
php_http_env_get_request_headers(Z_ARRVAL_P(return_value));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getRequestBody, 0, 0, 0)
ZEND_ARG_INFO(0, body_class_name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getRequestBody)
{
php_http_message_body_t *body;
php_http_message_body_object_t *body_obj;
zend_class_entry *class_entry = php_http_get_message_body_class_entry();
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|C", &class_entry), invalid_arg, return);
body = php_http_env_get_request_body();
if (SUCCESS == php_http_new((void *) &body_obj, class_entry, (php_http_new_t) php_http_message_body_object_new_ex, php_http_get_message_body_class_entry(), body)) {
php_http_message_body_addref(body);
RETVAL_OBJ(&body_obj->zo);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForCode, 0, 0, 1)
ZEND_ARG_INFO(0, code)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getResponseStatusForCode)
{
zend_long code;
const char *status;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code)) {
return;
}
if ((status = php_http_env_get_response_status_for_code(code))) {
RETURN_STRING(status);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseStatusForAllCodes, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getResponseStatusForAllCodes)
{
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
array_init(return_value);
#define PHP_HTTP_RESPONSE_CODE(code, status) add_index_string(return_value, code, status);
#include "php_http_response_codes.h"
#undef PHP_HTTP_RESPONSE_CODE
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseHeader, 0, 0, 0)
ZEND_ARG_INFO(0, header_name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getResponseHeader)
{
char *header_name_str = NULL;
size_t header_name_len = 0;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
return;
}
if (header_name_str && header_name_len) {
char *header_value = php_http_env_get_response_header(header_name_str, header_name_len);
if (header_value) {
RETURN_STR(php_http_cs2zs(header_value, strlen(header_value)));
}
} else {
array_init(return_value);
php_http_env_get_response_headers(Z_ARRVAL_P(return_value));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_getResponseCode, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, getResponseCode)
{
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
RETURN_LONG(php_http_env_get_response_code());
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseHeader, 0, 0, 1)
ZEND_ARG_INFO(0, header_name)
ZEND_ARG_INFO(0, header_value)
ZEND_ARG_INFO(0, response_code)
ZEND_ARG_INFO(0, replace_header)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, setResponseHeader)
{
char *header_name_str;
size_t header_name_len;
zval *header_value = NULL;
zend_long code = 0;
zend_bool replace_header = 1;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!lb", &header_name_str, &header_name_len, &header_value, &code, &replace_header)) {
return;
}
RETURN_BOOL(SUCCESS == php_http_env_set_response_header_value(code, header_name_str, header_name_len, header_value, replace_header));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_setResponseCode, 0, 0, 1)
ZEND_ARG_INFO(0, code)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, setResponseCode)
{
zend_long code;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "l", &code)) {
return;
}
RETURN_BOOL(SUCCESS == php_http_env_set_response_code(code));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateLanguage, 0, 0, 1)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(1, result_array)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, negotiateLanguage)
{
HashTable *supported;
zval *rs_array = NULL;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
PHP_HTTP_DO_NEGOTIATE(language, supported, rs_array);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateCharset, 0, 0, 1)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(1, result_array)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, negotiateCharset)
{
HashTable *supported;
zval *rs_array = NULL;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
PHP_HTTP_DO_NEGOTIATE(charset, supported, rs_array);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateEncoding, 0, 0, 1)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(1, result_array)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, negotiateEncoding)
{
HashTable *supported;
zval *rs_array = NULL;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiateContentType, 0, 0, 1)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(1, result_array)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, negotiateContentType)
{
HashTable *supported;
zval *rs_array = NULL;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
PHP_HTTP_DO_NEGOTIATE(content_type, supported, rs_array);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnv_negotiate, 0, 0, 2)
ZEND_ARG_INFO(0, params)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(0, primary_type_separator)
ZEND_ARG_INFO(1, result_array)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnv, negotiate)
{
HashTable *supported, *rs;
zval *rs_array = NULL;
char *value_str, *sep_str = NULL;
size_t value_len, sep_len = 0;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sH|s!z", &value_str, &value_len, &supported, &sep_str, &sep_len, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
if ((rs = php_http_negotiate(value_str, value_len, supported, sep_str, sep_len))) {
PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
} else {
PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
}
}
static zend_function_entry php_http_env_methods[] = {
PHP_ME(HttpEnv, getRequestHeader, ai_HttpEnv_getRequestHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, getRequestBody, ai_HttpEnv_getRequestBody, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, getResponseStatusForCode, ai_HttpEnv_getResponseStatusForCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, getResponseStatusForAllCodes, ai_HttpEnv_getResponseStatusForAllCodes, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, getResponseHeader, ai_HttpEnv_getResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, getResponseCode, ai_HttpEnv_getResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, setResponseHeader, ai_HttpEnv_setResponseHeader, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, setResponseCode, ai_HttpEnv_setResponseCode, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, negotiateLanguage, ai_HttpEnv_negotiateLanguage, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, negotiateContentType, ai_HttpEnv_negotiateContentType, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, negotiateEncoding, ai_HttpEnv_negotiateEncoding, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, negotiateCharset, ai_HttpEnv_negotiateCharset, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
PHP_ME(HttpEnv, negotiate, ai_HttpEnv_negotiate, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
EMPTY_FUNCTION_ENTRY
};
static zend_class_entry *php_http_env_class_entry;
zend_class_entry *php_http_env_get_class_entry(void)
{
return php_http_env_class_entry;
}
PHP_MINIT_FUNCTION(http_env)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Env", php_http_env_methods);
php_http_env_class_entry = zend_register_internal_class(&ce);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env.h 0000644 0001750 0000144 00000007344 12667772426 016032 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_ENV_H
#define PHP_HTTP_ENV_H
#include "php_http_message_body.h"
#include "php_http_version.h"
struct php_http_env_globals {
zval *server_var;
char *etag_mode;
struct {
HashTable *headers;
php_http_message_body_t *body;
} request;
};
typedef enum php_http_content_encoding {
PHP_HTTP_CONTENT_ENCODING_NONE,
PHP_HTTP_CONTENT_ENCODING_GZIP
} php_http_content_encoding_t;
typedef enum php_http_range_status {
PHP_HTTP_RANGE_NO,
PHP_HTTP_RANGE_OK,
PHP_HTTP_RANGE_ERR
} php_http_range_status_t;
PHP_HTTP_API php_http_range_status_t php_http_env_get_request_ranges(HashTable *ranges, size_t entity_length, php_http_message_t *request);
PHP_HTTP_API void php_http_env_get_request_headers(HashTable *headers);
PHP_HTTP_API char *php_http_env_get_request_header(const char *name_str, size_t name_len, size_t *len, php_http_message_t *request);
PHP_HTTP_API zend_bool php_http_env_got_request_header(const char *name_str, size_t name_len, php_http_message_t *request);
PHP_HTTP_API php_http_message_body_t *php_http_env_get_request_body(void);
PHP_HTTP_API const char *php_http_env_get_request_method(php_http_message_t *request);
typedef enum php_http_content_disposition {
PHP_HTTP_CONTENT_DISPOSITION_NONE,
PHP_HTTP_CONTENT_DISPOSITION_INLINE,
PHP_HTTP_CONTENT_DISPOSITION_ATTACHMENT
} php_http_content_disposition_t;
typedef enum php_http_cache_status {
PHP_HTTP_CACHE_NO,
PHP_HTTP_CACHE_HIT,
PHP_HTTP_CACHE_MISS
} php_http_cache_status_t;
PHP_HTTP_API long php_http_env_get_response_code(void);
PHP_HTTP_API const char *php_http_env_get_response_status_for_code(unsigned code);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_get_response_headers(HashTable *headers_ht);
PHP_HTTP_API char *php_http_env_get_response_header(const char *name_str, size_t name_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_code(long http_code);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_protocol_version(php_http_version_t *v);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header(long http_code, const char *header_str, size_t header_len, zend_bool replace);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_value(long http_code, const char *name_str, size_t name_len, zval *value, zend_bool replace);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_format(long http_code, zend_bool replace, const char *fmt, ...);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_set_response_header_va(long http_code, zend_bool replace, const char *fmt, va_list argv);
PHP_HTTP_API zval *php_http_env_get_server_var(const char *key_str, size_t key_len, zend_bool check);
PHP_HTTP_API zval *php_http_env_get_superglobal(const char *key, size_t key_len);
static inline zend_bool php_http_env_got_server_var(const char *v)
{
return NULL != php_http_env_get_server_var(v, strlen(v), 1);
}
PHP_HTTP_API zend_class_entry *php_http_env_get_class_entry(void);
PHP_MINIT_FUNCTION(http_env);
PHP_RSHUTDOWN_FUNCTION(http_env);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env_request.c 0000644 0001750 0000144 00000023270 12667772426 017571 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static int grab_file(zval *tmp_name, int argc, va_list argv, zend_hash_key *key)
{
zval *zfiles, *name, *zname, *error, *zerror, *type, *ztype, *size, *zsize;
zend_hash_key *file_key;
zfiles = (zval *) va_arg(argv, zval *);
file_key = (zend_hash_key *) va_arg(argv, zend_hash_key *);
name = (zval *) va_arg(argv, zval *);
size = (zval *) va_arg(argv, zval *);
type = (zval *) va_arg(argv, zval *);
error = (zval *) va_arg(argv, zval *);
if ((zname = zend_hash_index_find(Z_ARRVAL_P(name), key->h))
&& (zsize = zend_hash_index_find(Z_ARRVAL_P(size), key->h))
&& (ztype = zend_hash_index_find(Z_ARRVAL_P(type), key->h))
&& (zerror = zend_hash_index_find(Z_ARRVAL_P(error), key->h))
) {
zval entry, *array;
array_init(&entry);
Z_TRY_ADDREF_P(tmp_name);
add_assoc_zval_ex(&entry, ZEND_STRL("file"), tmp_name);
Z_TRY_ADDREF_P(zname);
add_assoc_zval_ex(&entry, ZEND_STRL("name"), zname);
Z_TRY_ADDREF_P(zsize);
add_assoc_zval_ex(&entry, ZEND_STRL("size"), zsize);
Z_TRY_ADDREF_P(ztype);
add_assoc_zval_ex(&entry, ZEND_STRL("type"), ztype);
Z_TRY_ADDREF_P(zerror);
add_assoc_zval_ex(&entry, ZEND_STRL("error"), zerror);
if (file_key->key && (array = zend_hash_find(Z_ARRVAL_P(zfiles), file_key->key))) {
add_next_index_zval(array, &entry);
} else if (!file_key->key && (array = zend_hash_index_find(Z_ARRVAL_P(zfiles), file_key->h))) {
add_next_index_zval(array, &entry);
} else {
zval tmp;
array_init(&tmp);
add_next_index_zval(&tmp, &entry);
if (file_key->key) {
zend_hash_update(Z_ARRVAL_P(zfiles), file_key->key, &tmp);
} else {
zend_hash_index_update(Z_ARRVAL_P(zfiles), file_key->h, &tmp);
}
}
}
return ZEND_HASH_APPLY_KEEP;
}
static int grab_files(zval *val, int argc, va_list argv, zend_hash_key *key)
{
zval *zfiles, *name, *tmp_name, *error, *type, *size;
zfiles = (zval *) va_arg(argv, zval *);
if ((Z_TYPE_P(val) == IS_ARRAY)
&& (tmp_name = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("tmp_name")))
&& (name = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("name")))
&& (size = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("size")))
&& (type = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("type")))
&& (error = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("error")))
) {
int count;
if (Z_TYPE_P(tmp_name) == IS_ARRAY && (count = zend_hash_num_elements(Z_ARRVAL_P(tmp_name))) > 1) {
if (count == zend_hash_num_elements(Z_ARRVAL_P(name))
&& count == zend_hash_num_elements(Z_ARRVAL_P(size))
&& count == zend_hash_num_elements(Z_ARRVAL_P(type))
&& count == zend_hash_num_elements(Z_ARRVAL_P(error))
) {
zend_hash_apply_with_arguments(Z_ARRVAL_P(tmp_name), grab_file, 6, zfiles, key, name, size, type, error);
} else {
/* wat?! */
return ZEND_HASH_APPLY_STOP;
}
} else {
zval *tmp, entry;
ZVAL_DUP(&entry, val);
if ((tmp = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("tmp_name")))) {
Z_ADDREF_P(tmp);
add_assoc_zval_ex(&entry, ZEND_STRL("file"), tmp);
zend_hash_str_del(Z_ARRVAL(entry), ZEND_STRL("tmp_name"));
}
if (key->key) {
zend_hash_update(Z_ARRVAL_P(zfiles), key->key, &entry);
} else {
zend_hash_index_update(Z_ARRVAL_P(zfiles), key->h, &entry);
}
}
}
return ZEND_HASH_APPLY_KEEP;
}
#define PHP_HTTP_ENV_REQUEST_OBJECT_INIT(obj) \
do { \
if (!obj->message) { \
obj->message = php_http_message_init_env(NULL, PHP_HTTP_REQUEST); \
} \
} while(0)
static zend_class_entry *php_http_env_request_class_entry;
zend_class_entry *php_http_get_env_request_class_entry(void)
{
return php_http_env_request_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest___construct, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvRequest, __construct)
{
php_http_message_object_t *obj;
zval *zsg, zqs;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
obj->body = NULL;
php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_REQUEST), unexpected_val, return);
zsg = php_http_env_get_superglobal(ZEND_STRL("_GET"));
object_init_ex(&zqs, php_http_querystring_get_class_entry());
php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return);
zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("query"), &zqs);
zval_ptr_dtor(&zqs);
zsg = php_http_env_get_superglobal(ZEND_STRL("_POST"));
object_init_ex(&zqs, php_http_querystring_get_class_entry());
php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return);
zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("form"), &zqs);
zval_ptr_dtor(&zqs);
zsg = php_http_env_get_superglobal(ZEND_STRL("_COOKIE"));
object_init_ex(&zqs, php_http_querystring_get_class_entry());
php_http_expect(SUCCESS == php_http_querystring_ctor(&zqs, zsg), unexpected_val, return);
zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("cookie"), &zqs);
zval_ptr_dtor(&zqs);
array_init(&zqs);
if ((zsg = php_http_env_get_superglobal(ZEND_STRL("_FILES")))) {
zend_hash_apply_with_arguments(Z_ARRVAL_P(zsg), grab_files, 1, &zqs);
}
zend_update_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("files"), &zqs);
zval_ptr_dtor(&zqs);
}
#define call_querystring_get(prop) \
do {\
zend_fcall_info fci; \
zend_fcall_info_cache fcc; \
zval rv, mn, *args = ecalloc(sizeof(zval), ZEND_NUM_ARGS()); \
zval *this_ptr = getThis(); \
zval qs_tmp, *qs = zend_read_property(Z_OBJCE_P(this_ptr), this_ptr, ZEND_STRL(prop), 0, &qs_tmp); \
\
ZVAL_NULL(&rv); \
array_init(&mn); \
Z_TRY_ADDREF_P(qs); \
add_next_index_zval(&mn, qs); \
add_next_index_stringl(&mn, ZEND_STRL("get")); \
zend_fcall_info_init(&mn, 0, &fci, &fcc, NULL, NULL); \
zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args); \
zend_fcall_info_argp(&fci, ZEND_NUM_ARGS(), args); \
zend_fcall_info_call(&fci, &fcc, &rv, NULL); \
zend_fcall_info_args_clear(&fci, 1); \
efree(args); \
zval_dtor(&mn); \
RETVAL_ZVAL(&rv, 0, 1); \
} while(0);
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getForm, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, defval)
ZEND_ARG_INFO(0, delete)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvRequest, getForm)
{
if (ZEND_NUM_ARGS()) {
call_querystring_get("form");
} else {
zval zform_tmp, *zform = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("form"), 0, &zform_tmp);
RETURN_ZVAL(zform, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getQuery, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, defval)
ZEND_ARG_INFO(0, delete)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvRequest, getQuery)
{
if (ZEND_NUM_ARGS()) {
call_querystring_get("query");
} else {
zval zquery_tmp, *zquery = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("query"), 0, &zquery_tmp);
RETURN_ZVAL(zquery, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getCookie, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, defval)
ZEND_ARG_INFO(0, delete)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvRequest, getCookie)
{
if (ZEND_NUM_ARGS()) {
call_querystring_get("cookie");
} else {
zval zcookie_tmp, *zcookie = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("cookie"), 0, &zcookie_tmp);
RETURN_ZVAL(zcookie, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvRequest_getFiles, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvRequest, getFiles)
{
if (SUCCESS == zend_parse_parameters_none()) {
zval zfiles_tmp, *zfiles = zend_read_property(php_http_env_request_class_entry, getThis(), ZEND_STRL("files"), 0, &zfiles_tmp);
RETURN_ZVAL(zfiles, 1, 0);
}
}
static zend_function_entry php_http_env_request_methods[] = {
PHP_ME(HttpEnvRequest, __construct, ai_HttpEnvRequest___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpEnvRequest, getForm, ai_HttpEnvRequest_getForm, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvRequest, getQuery, ai_HttpEnvRequest_getQuery, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvRequest, getCookie, ai_HttpEnvRequest_getCookie, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvRequest, getFiles, ai_HttpEnvRequest_getFiles, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_env_request)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Request", php_http_env_request_methods);
php_http_env_request_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry());
zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("query"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("form"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("cookie"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_request_class_entry, ZEND_STRL("files"), ZEND_ACC_PROTECTED);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env_request.h 0000644 0001750 0000144 00000001753 12667772426 017600 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_ENV_REQUEST_H
#define PHP_HTTP_ENV_REQUEST_H
PHP_HTTP_API zend_class_entry *php_http_get_env_request_class_entry(void);
PHP_MINIT_FUNCTION(http_env_request);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env_response.c 0000644 0001750 0000144 00000130104 12667772426 017732 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static void set_option(zval *options, const char *name_str, size_t name_len, int type, void *value_ptr, size_t value_len)
{
if (Z_TYPE_P(options) == IS_OBJECT) {
if (value_ptr) {
switch (type) {
case IS_DOUBLE:
zend_update_property_double(Z_OBJCE_P(options), options, name_str, name_len, *(double *)value_ptr);
break;
case IS_LONG:
zend_update_property_long(Z_OBJCE_P(options), options, name_str, name_len, *(zend_long *)value_ptr);
break;
case IS_STRING:
zend_update_property_stringl(Z_OBJCE_P(options), options, name_str, name_len, value_ptr, value_len);
break;
case IS_ARRAY:
case IS_OBJECT:
zend_update_property(Z_OBJCE_P(options), options, name_str, name_len, value_ptr);
break;
}
} else {
zend_update_property_null(Z_OBJCE_P(options), options, name_str, name_len);
}
} else {
convert_to_array(options);
if (value_ptr) {
switch (type) {
case IS_DOUBLE:
add_assoc_double_ex(options, name_str, name_len, *(double *)value_ptr);
break;
case IS_LONG:
add_assoc_long_ex(options, name_str, name_len, *(zend_long *)value_ptr);
break;
case IS_STRING: {
zend_string *value = zend_string_init(value_ptr, value_len, 0);
add_assoc_str_ex(options, name_str, name_len, value);
break;
case IS_ARRAY:
case IS_OBJECT:
Z_ADDREF_P(value_ptr);
add_assoc_zval_ex(options, name_str, name_len, value_ptr);
break;
}
}
} else {
add_assoc_null_ex(options, name_str, name_len);
}
}
}
static zval *get_option(zval *options, const char *name_str, size_t name_len, zval *tmp)
{
zval *val = NULL;
if (Z_TYPE_P(options) == IS_OBJECT) {
val = zend_read_property(Z_OBJCE_P(options), options, name_str, name_len, 0, tmp);
} else if (Z_TYPE_P(options) == IS_ARRAY) {
val = zend_symtable_str_find(Z_ARRVAL_P(options), name_str, name_len);
} else {
abort();
}
if (val) {
Z_TRY_ADDREF_P(val);
}
return val;
}
static php_http_message_body_t *get_body(zval *options)
{
zval zbody_tmp, *zbody;
php_http_message_body_t *body = NULL;
if ((zbody = get_option(options, ZEND_STRL("body"), &zbody_tmp))) {
if ((Z_TYPE_P(zbody) == IS_OBJECT) && instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) {
php_http_message_body_object_t *body_obj = PHP_HTTP_OBJ(NULL, zbody);
body = body_obj->body;
}
Z_TRY_DELREF_P(zbody);
}
return body;
}
static php_http_message_t *get_request(zval *options)
{
zval zrequest_tmp, *zrequest;
php_http_message_t *request = NULL;
if ((zrequest = get_option(options, ZEND_STRL("request"), &zrequest_tmp))) {
if (Z_TYPE_P(zrequest) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zrequest), php_http_message_get_class_entry())) {
php_http_message_object_t *request_obj = PHP_HTTP_OBJ(NULL, zrequest);
request = request_obj->message;
}
Z_TRY_DELREF_P(zrequest);
}
return request;
}
static void set_cookie(zval *options, zval *zcookie_new)
{
zval tmp, zcookies_set_tmp, *zcookies_set;
php_http_arrkey_t key;
php_http_cookie_object_t *obj = PHP_HTTP_OBJ(NULL, zcookie_new);
array_init(&tmp);
zcookies_set = get_option(options, ZEND_STRL("cookies"), &zcookies_set_tmp);
if (zcookies_set && Z_TYPE_P(zcookies_set) == IS_ARRAY) {
array_copy(Z_ARRVAL_P(zcookies_set), Z_ARRVAL(tmp));
zval_ptr_dtor(zcookies_set);
}
ZEND_HASH_FOREACH_KEY(&obj->list->cookies, key.h, key.key)
{
Z_ADDREF_P(zcookie_new);
if (key.key) {
add_assoc_zval_ex(&tmp, key.key->val, key.key->len, zcookie_new);
} else {
add_index_zval(&tmp, key.h, zcookie_new);
}
}
ZEND_HASH_FOREACH_END();
set_option(options, ZEND_STRL("cookies"), IS_ARRAY, &tmp, 0);
zval_ptr_dtor(&tmp);
}
php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request)
{
php_http_cache_status_t ret = PHP_HTTP_CACHE_NO;
char *header = NULL, *etag = NULL;
php_http_message_body_t *body;
zval zetag_tmp, *zetag;
if (!(body = get_body(options))) {
return ret;
}
if ((zetag = get_option(options, ZEND_STRL("etag"), &zetag_tmp)) && Z_TYPE_P(zetag) != IS_NULL) {
zend_string *zs = zval_get_string(zetag);
etag = estrndup(zs->val, zs->len);
zend_string_release(zs);
zval_ptr_dtor(zetag);
}
if (!etag && (etag = php_http_message_body_etag(body))) {
set_option(options, ZEND_STRL("etag"), IS_STRING, etag, strlen(etag));
}
if (etag && (header = php_http_env_get_request_header(header_str, header_len, NULL, request))) {
ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD) ? PHP_HTTP_CACHE_HIT : PHP_HTTP_CACHE_MISS;
}
PTR_FREE(etag);
PTR_FREE(header);
return ret;
}
php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request)
{
php_http_cache_status_t ret = PHP_HTTP_CACHE_NO;
char *header;
time_t ums, lm = 0;
php_http_message_body_t *body;
zval zlm_tmp, *zlm;
if (!(body = get_body(options))) {
return ret;
}
if ((zlm = get_option(options, ZEND_STRL("lastModified"), &zlm_tmp))) {
lm = zval_get_long(zlm);
zval_ptr_dtor(zlm);
}
if (lm <= 0) {
lm = php_http_message_body_mtime(body);
set_option(options, ZEND_STRL("lastModified"), IS_LONG, &lm, 0);
}
if ((header = php_http_env_get_request_header(header_str, header_len, NULL, request))) {
ums = php_parse_date(header, NULL);
if (ums > 0 && ums >= lm) {
ret = PHP_HTTP_CACHE_HIT;
} else {
ret = PHP_HTTP_CACHE_MISS;
}
}
PTR_FREE(header);
return ret;
}
static zend_bool php_http_env_response_is_cacheable(php_http_env_response_t *r, php_http_message_t *request)
{
long status = r->ops->get_status(r);
if (status && status / 100 != 2) {
return 0;
}
if (php_http_env_got_request_header(ZEND_STRL("Authorization"), request)) {
return 0;
}
if (-1 == php_http_select_str(php_http_env_get_request_method(request), 2, "HEAD", "GET")) {
return 0;
}
return 1;
}
static size_t output(void *context, char *buf, size_t len)
{
php_http_env_response_t *r = context;
if (SUCCESS != r->ops->write(r, buf, len)) {
return (size_t) -1;
}
/* we really only need to flush when throttling is enabled,
because we push the data as fast as possible anyway if not */
if (r->throttle.delay >= PHP_HTTP_DIFFSEC) {
r->ops->flush(r);
php_http_sleep(r->throttle.delay);
}
return len;
}
static ZEND_RESULT_CODE php_http_env_response_send_data(php_http_env_response_t *r, const char *buf, size_t len)
{
size_t chunks_sent, chunk = r->throttle.chunk ? r->throttle.chunk : PHP_HTTP_SENDBUF_SIZE;
if (r->content.encoder) {
char *enc_str = NULL;
size_t enc_len = 0;
if (buf) {
if (SUCCESS != php_http_encoding_stream_update(r->content.encoder, buf, len, &enc_str, &enc_len)) {
return FAILURE;
}
} else {
if (SUCCESS != php_http_encoding_stream_finish(r->content.encoder, &enc_str, &enc_len)) {
return FAILURE;
}
}
if (!enc_str) {
return SUCCESS;
}
chunks_sent = php_http_buffer_chunked_output(&r->buffer, enc_str, enc_len, buf ? chunk : 0, output, r);
PTR_FREE(enc_str);
} else {
chunks_sent = php_http_buffer_chunked_output(&r->buffer, buf, len, buf ? chunk : 0, output, r);
}
return chunks_sent != (size_t) -1 ? SUCCESS : FAILURE;
}
static inline ZEND_RESULT_CODE php_http_env_response_send_done(php_http_env_response_t *r)
{
return php_http_env_response_send_data(r, NULL, 0);
}
php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *init_arg)
{
zend_bool free_r;
if ((free_r = !r)) {
r = emalloc(sizeof(*r));
}
memset(r, 0, sizeof(*r));
if (ops) {
r->ops = ops;
} else {
r->ops = php_http_env_response_get_sapi_ops();
}
r->buffer = php_http_buffer_init(NULL);
ZVAL_COPY(&r->options, options);
if (r->ops->init && (SUCCESS != r->ops->init(r, init_arg))) {
if (free_r) {
php_http_env_response_free(&r);
} else {
php_http_env_response_dtor(r);
r = NULL;
}
}
return r;
}
void php_http_env_response_dtor(php_http_env_response_t *r)
{
if (r->ops->dtor) {
r->ops->dtor(r);
}
php_http_buffer_free(&r->buffer);
zval_ptr_dtor(&r->options);
PTR_FREE(r->content.type);
PTR_FREE(r->content.encoding);
if (r->content.encoder) {
php_http_encoding_stream_free(&r->content.encoder);
}
}
void php_http_env_response_free(php_http_env_response_t **r)
{
if (*r) {
php_http_env_response_dtor(*r);
efree(*r);
*r = NULL;
}
}
static ZEND_RESULT_CODE php_http_env_response_send_head(php_http_env_response_t *r, php_http_message_t *request)
{
ZEND_RESULT_CODE ret = SUCCESS;
zval zoption_tmp, *zoption, *options = &r->options;
if (r->done) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("headers"), &zoption_tmp))) {
if (Z_TYPE_P(zoption) == IS_ARRAY) {
php_http_header_to_callback(Z_ARRVAL_P(zoption), 0, (php_http_pass_format_callback_t) r->ops->set_header, r);
}
zval_ptr_dtor(zoption);
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("responseCode"), &zoption_tmp))) {
zend_long rc = zval_get_long(zoption);
zval_ptr_dtor(zoption);
if (rc > 0) {
ret = r->ops->set_status(r, rc);
}
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("httpVersion"), &zoption_tmp))) {
php_http_version_t v;
zend_string *zs = zval_get_string(zoption);
zval_ptr_dtor(zoption);
if (zs->len && php_http_version_parse(&v, zs->val)) {
ret = r->ops->set_protocol_version(r, &v);
php_http_version_dtor(&v);
}
zend_string_release(zs);
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("cookies"), &zoption_tmp))) {
if (Z_TYPE_P(zoption) == IS_ARRAY) {
zval *zcookie;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zoption), zcookie)
{
if (Z_TYPE_P(zcookie) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_get_class_entry())) {
php_http_cookie_object_t *obj = PHP_HTTP_OBJ(NULL, zcookie);
char *str;
size_t len;
php_http_cookie_list_to_string(obj->list, &str, &len);
if (SUCCESS != (ret = r->ops->add_header(r, "Set-Cookie: %s", str))) {
efree(str);
break;
}
efree(str);
}
}
ZEND_HASH_FOREACH_END();
}
zval_ptr_dtor(zoption);
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("contentType"), &zoption_tmp))) {
zend_string *zs = zval_get_string(zoption);
zval_ptr_dtor(zoption);
if (zs->len && strchr(zs->val, '/')) {
if (SUCCESS == (ret = r->ops->set_header(r, "Content-Type: %.*s", zs->len, zs->val))) {
r->content.type = estrndup(zs->val, zs->len);
}
}
zend_string_release(zs);
}
if (ret != SUCCESS) {
return ret;
}
if (r->range.status == PHP_HTTP_RANGE_OK) {
if (zend_hash_num_elements(&r->range.values) == 1) {
zval *range, *begin, *end;
if ( 1 == php_http_array_list(&r->range.values, 1, &range)
&& 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end)
) {
if (SUCCESS == (ret = r->ops->set_status(r, 206))) {
ret = r->ops->set_header(r, "Content-Range: bytes %ld-%ld/%zu", Z_LVAL_P(begin), Z_LVAL_P(end), r->content.length);
}
} else {
/* this should never happen */
zend_hash_destroy(&r->range.values);
ret = FAILURE;
}
} else {
php_http_boundary(r->range.boundary, sizeof(r->range.boundary));
if (SUCCESS == (ret = r->ops->set_status(r, 206))) {
ret = r->ops->set_header(r, "Content-Type: multipart/byteranges; boundary=%s", r->range.boundary);
}
}
} else {
if ((zoption = get_option(options, ZEND_STRL("cacheControl"), &zoption_tmp))) {
zend_string *zs = zval_get_string(zoption);
zval_ptr_dtor(zoption);
if (zs->len) {
ret = r->ops->set_header(r, "Cache-Control: %.*s", zs->len, zs->val);
}
zend_string_release(zs);
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("contentDisposition"), &zoption_tmp))) {
if (Z_TYPE_P(zoption) == IS_ARRAY) {
php_http_buffer_t buf;
php_http_buffer_init(&buf);
if (php_http_params_to_string(&buf, Z_ARRVAL_P(zoption), ZEND_STRL(","), ZEND_STRL(";"), ZEND_STRL("="), PHP_HTTP_PARAMS_DEFAULT)) {
if (buf.used) {
ret = r->ops->set_header(r, "Content-Disposition: %.*s", buf.used, buf.data);
}
}
php_http_buffer_dtor(&buf);
}
zval_ptr_dtor(zoption);
}
if (ret != SUCCESS) {
return ret;
}
if ((zoption = get_option(options, ZEND_STRL("contentEncoding"), &zoption_tmp))) {
zend_long ce = zval_get_long(zoption);
zval zsupported;
HashTable *result = NULL;
zval_ptr_dtor(zoption);
switch (ce) {
case PHP_HTTP_CONTENT_ENCODING_GZIP:
array_init(&zsupported);
add_next_index_stringl(&zsupported, ZEND_STRL("none"));
add_next_index_stringl(&zsupported, ZEND_STRL("gzip"));
add_next_index_stringl(&zsupported, ZEND_STRL("deflate"));
if ((result = php_http_negotiate_encoding(Z_ARRVAL(zsupported), request))) {
zend_string *key_str = NULL;
zend_ulong index = 0;
zend_hash_internal_pointer_reset(result);
if (HASH_KEY_IS_STRING == zend_hash_get_current_key(result, &key_str, &index)) {
if (zend_string_equals_literal(key_str, "gzip")) {
if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_GZIP))) {
ret = FAILURE;
} else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: gzip"))) {
r->content.encoding = estrndup(key_str->val, key_str->len);
}
} else if (zend_string_equals_literal(key_str, "deflate")) {
if (!(r->content.encoder = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), PHP_HTTP_DEFLATE_TYPE_ZLIB))) {
ret = FAILURE;
} else if (SUCCESS == (ret = r->ops->set_header(r, "Content-Encoding: deflate"))) {
r->content.encoding = estrndup(key_str->val, key_str->len);
}
} else {
ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding"));
}
if (SUCCESS == ret) {
ret = r->ops->add_header(r, "Vary: Accept-Encoding");
}
}
zend_hash_destroy(result);
FREE_HASHTABLE(result);
}
zval_dtor(&zsupported);
break;
case PHP_HTTP_CONTENT_ENCODING_NONE:
default:
ret = r->ops->del_header(r, ZEND_STRL("Content-Encoding"));
break;
}
}
if (SUCCESS != ret) {
return ret;
}
if (php_http_env_response_is_cacheable(r, request)) {
switch (php_http_env_is_response_cached_by_etag(options, ZEND_STRL("If-None-Match"), request)) {
case PHP_HTTP_CACHE_MISS:
break;
case PHP_HTTP_CACHE_NO:
if (PHP_HTTP_CACHE_HIT != php_http_env_is_response_cached_by_last_modified(options, ZEND_STRL("If-Modified-Since"), request)) {
break;
}
/* no break */
case PHP_HTTP_CACHE_HIT:
ret = r->ops->set_status(r, 304);
r->done = 1;
break;
}
if ((zoption = get_option(options, ZEND_STRL("etag"), &zoption_tmp))) {
zend_string *zs = zval_get_string(zoption);
zval_ptr_dtor(zoption);
if (*zs->val != '"' && strncmp(zs->val, "W/\"", 3)) {
ret = r->ops->set_header(r, "ETag: \"%s\"", zs->val);
} else {
ret = r->ops->set_header(r, "ETag: %s", zs->val);
}
zend_string_release(zs);
}
if ((zoption = get_option(options, ZEND_STRL("lastModified"), &zoption_tmp))) {
zend_long lm = zval_get_long(zoption);
zval_ptr_dtor(zoption);
if (lm) {
zend_string *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), lm, 0);
if (date) {
ret = r->ops->set_header(r, "Last-Modified: %s", date->val);
zend_string_release(date);
}
}
}
}
}
return ret;
}
static ZEND_RESULT_CODE php_http_env_response_send_body(php_http_env_response_t *r)
{
ZEND_RESULT_CODE ret = SUCCESS;
zval zoption_tmp, *zoption;
php_http_message_body_t *body;
if (r->done) {
return ret;
}
if ((body = get_body(&r->options))) {
if ((zoption = get_option(&r->options, ZEND_STRL("throttleDelay"), &zoption_tmp))) {
r->throttle.delay = zval_get_double(zoption);
zval_ptr_dtor(zoption);
}
if ((zoption = get_option(&r->options, ZEND_STRL("throttleChunk"), &zoption_tmp))) {
r->throttle.chunk = zval_get_long(zoption);
zval_ptr_dtor(zoption);
}
if (r->range.status == PHP_HTTP_RANGE_OK) {
if (zend_hash_num_elements(&r->range.values) == 1) {
/* single range */
zval *range, *begin, *end;
if ( 1 == php_http_array_list(&r->range.values, 1, &range)
&& 2 == php_http_array_list(Z_ARRVAL_P(range), 2, &begin, &end)
) {
/* send chunk */
ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_P(begin), Z_LVAL_P(end) - Z_LVAL_P(begin) + 1);
if (ret == SUCCESS) {
ret = php_http_env_response_send_done(r);
}
zend_hash_destroy(&r->range.values);
} else {
/* this should never happen */
zend_hash_destroy(&r->range.values);
r->ops->set_status(r, 500);
ret = FAILURE;
}
} else {
/* send multipart/byte-ranges message */
zval *chunk;
ZEND_HASH_FOREACH_VAL(&r->range.values, chunk)
{
zval *begin, *end;
if (2 == php_http_array_list(Z_ARRVAL_P(chunk), 2, &begin, &end)) {
php_http_buffer_appendf(r->buffer,
PHP_HTTP_CRLF
"--%s" PHP_HTTP_CRLF
"Content-Type: %s" PHP_HTTP_CRLF
"Content-Range: bytes %ld-%ld/%zu" PHP_HTTP_CRLF PHP_HTTP_CRLF,
/* - */
r->range.boundary,
r->content.type ? r->content.type : "application/octet-stream",
Z_LVAL_P(begin),
Z_LVAL_P(end),
r->content.length
);
ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, Z_LVAL_P(begin), Z_LVAL_P(end) - Z_LVAL_P(begin) + 1);
}
}
ZEND_HASH_FOREACH_END();
if (ret == SUCCESS) {
php_http_buffer_appendf(r->buffer, PHP_HTTP_CRLF "--%s--", r->range.boundary);
ret = php_http_env_response_send_done(r);
}
zend_hash_destroy(&r->range.values);
}
} else {
ret = php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_env_response_send_data, r, 0, 0);
if (ret == SUCCESS) {
ret = php_http_env_response_send_done(r);
}
}
}
return ret;
}
ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r)
{
php_http_message_t *request;
php_http_message_body_t *body;
request = get_request(&r->options);
/* check for ranges */
if ((body = get_body(&r->options))) {
r->content.length = php_http_message_body_size(body);
if (SUCCESS != r->ops->set_header(r, "Accept-Ranges: bytes")) {
return FAILURE;
} else {
ZEND_INIT_SYMTABLE_EX(&r->range.values, 0, 0);
r->range.status = php_http_env_get_request_ranges(&r->range.values, r->content.length, request);
switch (r->range.status) {
case PHP_HTTP_RANGE_NO:
zend_hash_destroy(&r->range.values);
break;
case PHP_HTTP_RANGE_ERR:
if (php_http_env_got_request_header(ZEND_STRL("If-Range"), request)) {
r->range.status = PHP_HTTP_RANGE_NO;
zend_hash_destroy(&r->range.values);
} else {
r->done = 1;
zend_hash_destroy(&r->range.values);
if (SUCCESS != r->ops->set_status(r, 416)) {
return FAILURE;
}
if (SUCCESS != r->ops->set_header(r, "Content-Range: bytes */%zu", r->content.length)) {
return FAILURE;
}
}
break;
case PHP_HTTP_RANGE_OK:
if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(&r->options, ZEND_STRL("If-Range"), request)
|| PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("If-Range"), request)
) {
r->range.status = PHP_HTTP_RANGE_NO;
zend_hash_destroy(&r->range.values);
break;
}
if (PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_etag(&r->options, ZEND_STRL("If-Match"), request)
|| PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("If-Unmodified-Since"), request)
|| PHP_HTTP_CACHE_MISS == php_http_env_is_response_cached_by_last_modified(&r->options, ZEND_STRL("Unless-Modified-Since"), request)
) {
r->done = 1;
zend_hash_destroy(&r->range.values);
if (SUCCESS != r->ops->set_status(r, 412)) {
return FAILURE;
}
break;
}
break;
}
}
}
if (SUCCESS != php_http_env_response_send_head(r, request)) {
php_error_docref(NULL, E_WARNING, "Failed to send response headers");
return FAILURE;
}
if (SUCCESS != php_http_env_response_send_body(r)) {
php_error_docref(NULL, E_WARNING, "Failed to send response body");
return FAILURE;
}
if (SUCCESS != r->ops->finish(r)) {
php_error_docref(NULL, E_WARNING, "Failed to finish response");
return FAILURE;
}
return SUCCESS;
}
static long php_http_env_response_sapi_get_status(php_http_env_response_t *r)
{
return php_http_env_get_response_code();
}
static ZEND_RESULT_CODE php_http_env_response_sapi_set_status(php_http_env_response_t *r, long http_code)
{
return php_http_env_set_response_code(http_code);
}
static ZEND_RESULT_CODE php_http_env_response_sapi_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
{
return php_http_env_set_response_protocol_version(v);
}
static ZEND_RESULT_CODE php_http_env_response_sapi_set_header(php_http_env_response_t *r, const char *fmt, ...)
{
ZEND_RESULT_CODE ret;
va_list args;
va_start(args, fmt);
ret = php_http_env_set_response_header_va(0, 1, fmt, args);
va_end(args);
return ret;
}
static ZEND_RESULT_CODE php_http_env_response_sapi_add_header(php_http_env_response_t *r, const char *fmt, ...)
{
ZEND_RESULT_CODE ret;
va_list args;
va_start(args, fmt);
ret = php_http_env_set_response_header_va(0, 0, fmt, args);
va_end(args);
return ret;
}
static ZEND_RESULT_CODE php_http_env_response_sapi_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
{
return php_http_env_set_response_header_value(0, header_str, header_len, NULL, 1);
}
static ZEND_RESULT_CODE php_http_env_response_sapi_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
{
if (0 < PHPWRITE(data_str, data_len)) {
return SUCCESS;
}
return FAILURE;
}
static ZEND_RESULT_CODE php_http_env_response_sapi_flush(php_http_env_response_t *r)
{
if (php_output_get_level()) {
php_output_flush_all();
}
if (!(php_output_get_status() & PHP_OUTPUT_IMPLICITFLUSH)) {
sapi_flush();
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_env_response_sapi_finish(php_http_env_response_t *r)
{
return SUCCESS;
}
static php_http_env_response_ops_t php_http_env_response_sapi_ops = {
NULL,
NULL,
php_http_env_response_sapi_get_status,
php_http_env_response_sapi_set_status,
php_http_env_response_sapi_set_protocol_version,
php_http_env_response_sapi_set_header,
php_http_env_response_sapi_add_header,
php_http_env_response_sapi_del_header,
php_http_env_response_sapi_write,
php_http_env_response_sapi_flush,
php_http_env_response_sapi_finish
};
php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void)
{
return &php_http_env_response_sapi_ops;
}
typedef struct php_http_env_response_stream_ctx {
HashTable header;
php_http_version_t version;
long status_code;
php_stream *stream;
php_stream_filter *chunked_filter;
php_http_message_t *request;
unsigned started:1;
unsigned finished:1;
unsigned chunked:1;
} php_http_env_response_stream_ctx_t;
static ZEND_RESULT_CODE php_http_env_response_stream_init(php_http_env_response_t *r, void *init_arg)
{
php_http_env_response_stream_ctx_t *ctx;
size_t buffer_size = 0x1000;
ctx = ecalloc(1, sizeof(*ctx));
ctx->stream = init_arg;
++GC_REFCOUNT(ctx->stream->res);
ZEND_INIT_SYMTABLE(&ctx->header);
php_http_version_init(&ctx->version, 1, 1);
php_stream_set_option(ctx->stream, PHP_STREAM_OPTION_WRITE_BUFFER, PHP_STREAM_BUFFER_FULL, &buffer_size);
ctx->status_code = 200;
ctx->chunked = 1;
ctx->request = get_request(&r->options);
/* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
if (ctx->request && ctx->request->http.version.major == 1 && ctx->request->http.version.minor == 0) {
ctx->version.minor = 0;
}
r->ctx = ctx;
return SUCCESS;
}
static void php_http_env_response_stream_dtor(php_http_env_response_t *r)
{
php_http_env_response_stream_ctx_t *ctx = r->ctx;
if (ctx->chunked_filter) {
ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1);
}
zend_hash_destroy(&ctx->header);
zend_list_delete(ctx->stream->res);
efree(ctx);
r->ctx = NULL;
}
static void php_http_env_response_stream_header(php_http_env_response_stream_ctx_t *ctx, HashTable *header, php_http_buffer_t *buf)
{
zval *val;
ZEND_HASH_FOREACH_VAL(header, val)
{
if (Z_TYPE_P(val) == IS_ARRAY) {
php_http_env_response_stream_header(ctx, Z_ARRVAL_P(val), buf);
} else {
zend_string *zs = zval_get_string(val);
if (ctx->chunked) {
/* disable chunked transfer encoding if we've got an explicit content-length */
if (!strncasecmp(zs->val, "Content-Length:", lenof("Content-Length:"))) {
ctx->chunked = 0;
}
}
php_http_buffer_append(buf, zs->val, zs->len);
php_http_buffer_appends(buf, PHP_HTTP_CRLF);
zend_string_release(zs);
}
}
ZEND_HASH_FOREACH_END();
}
static ZEND_RESULT_CODE php_http_env_response_stream_start(php_http_env_response_stream_ctx_t *ctx)
{
php_http_buffer_t header_buf;
if (ctx->started || ctx->finished) {
return FAILURE;
}
php_http_buffer_init(&header_buf);
php_http_buffer_appendf(&header_buf, "HTTP/%u.%u %ld %s" PHP_HTTP_CRLF, ctx->version.major, ctx->version.minor, ctx->status_code, php_http_env_get_response_status_for_code(ctx->status_code));
/* there are some limitations regarding TE:chunked, see https://tools.ietf.org/html/rfc7230#section-3.3.1 */
if (ctx->version.major == 1 && ctx->version.minor == 0) {
ctx->chunked = 0;
} else if (ctx->status_code == 204 || ctx->status_code/100 == 1) {
ctx->chunked = 0;
} else if (ctx->request && ctx->status_code/100 == 2 && !strcasecmp(ctx->request->http.info.request.method, "CONNECT")) {
ctx->chunked = 0;
}
php_http_env_response_stream_header(ctx, &ctx->header, &header_buf);
/* enable chunked transfer encoding */
if (ctx->chunked) {
php_http_buffer_appends(&header_buf, "Transfer-Encoding: chunked" PHP_HTTP_CRLF);
}
php_http_buffer_appends(&header_buf, PHP_HTTP_CRLF);
if (header_buf.used == php_stream_write(ctx->stream, header_buf.data, header_buf.used)) {
ctx->started = 1;
}
php_http_buffer_dtor(&header_buf);
php_stream_flush(ctx->stream);
if (ctx->chunked) {
ctx->chunked_filter = php_stream_filter_create("http.chunked_encode", NULL, 0);
php_stream_filter_append(&ctx->stream->writefilters, ctx->chunked_filter);
}
return ctx->started ? SUCCESS : FAILURE;
}
static long php_http_env_response_stream_get_status(php_http_env_response_t *r)
{
php_http_env_response_stream_ctx_t *ctx = r->ctx;
return ctx->status_code;
}
static ZEND_RESULT_CODE php_http_env_response_stream_set_status(php_http_env_response_t *r, long http_code)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
if (stream_ctx->started || stream_ctx->finished) {
return FAILURE;
}
stream_ctx->status_code = http_code;
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_env_response_stream_set_protocol_version(php_http_env_response_t *r, php_http_version_t *v)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
if (stream_ctx->started || stream_ctx->finished) {
return FAILURE;
}
memcpy(&stream_ctx->version, v, sizeof(stream_ctx->version));
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_env_response_stream_set_header_ex(php_http_env_response_t *r, zend_bool replace, const char *fmt, va_list argv)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
char *header_end, *header_str = NULL;
size_t header_len = 0;
zval zheader, *zheader_ptr;
zend_string *header_key;
ZEND_RESULT_CODE rv;
if (stream_ctx->started || stream_ctx->finished) {
return FAILURE;
}
header_len = vspprintf(&header_str, 0, fmt, argv);
if (!(header_end = strchr(header_str, ':'))) {
efree(header_str);
return FAILURE;
}
header_key = zend_string_init(header_str, header_end - header_str, 0);
if (!replace && (zheader_ptr = zend_hash_find(&stream_ctx->header, header_key))) {
convert_to_array(zheader_ptr);
rv = add_next_index_str(zheader_ptr, php_http_cs2zs(header_str, header_len));
} else {
ZVAL_STR(&zheader, php_http_cs2zs(header_str, header_len));
rv = zend_hash_update(&stream_ctx->header, header_key, &zheader)
? SUCCESS : FAILURE;
}
zend_string_release(header_key);
return rv;
}
static ZEND_RESULT_CODE php_http_env_response_stream_set_header(php_http_env_response_t *r, const char *fmt, ...)
{
ZEND_RESULT_CODE ret;
va_list argv;
va_start(argv, fmt);
ret = php_http_env_response_stream_set_header_ex(r, 1, fmt, argv);
va_end(argv);
return ret;
}
static ZEND_RESULT_CODE php_http_env_response_stream_add_header(php_http_env_response_t *r, const char *fmt, ...)
{
ZEND_RESULT_CODE ret;
va_list argv;
va_start(argv, fmt);
ret = php_http_env_response_stream_set_header_ex(r, 0, fmt, argv);
va_end(argv);
return ret;
}
static ZEND_RESULT_CODE php_http_env_response_stream_del_header(php_http_env_response_t *r, const char *header_str, size_t header_len)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
if (stream_ctx->started || stream_ctx->finished) {
return FAILURE;
}
zend_hash_str_del(&stream_ctx->header, header_str, header_len);
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_env_response_stream_write(php_http_env_response_t *r, const char *data_str, size_t data_len)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
if (stream_ctx->finished) {
return FAILURE;
}
if (!stream_ctx->started) {
if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) {
return FAILURE;
}
}
if (data_len != php_stream_write(stream_ctx->stream, data_str, data_len)) {
return FAILURE;
}
return SUCCESS;
}
static ZEND_RESULT_CODE php_http_env_response_stream_flush(php_http_env_response_t *r)
{
php_http_env_response_stream_ctx_t *stream_ctx = r->ctx;
if (stream_ctx->finished) {
return FAILURE;
}
if (!stream_ctx->started) {
if (SUCCESS != php_http_env_response_stream_start(stream_ctx)) {
return FAILURE;
}
}
return php_stream_flush(stream_ctx->stream);
}
static ZEND_RESULT_CODE php_http_env_response_stream_finish(php_http_env_response_t *r)
{
php_http_env_response_stream_ctx_t *ctx = r->ctx;
if (ctx->finished) {
return FAILURE;
}
if (!ctx->started) {
if (SUCCESS != php_http_env_response_stream_start(ctx)) {
return FAILURE;
}
}
php_stream_flush(ctx->stream);
if (ctx->chunked && ctx->chunked_filter) {
php_stream_filter_flush(ctx->chunked_filter, 1);
ctx->chunked_filter = php_stream_filter_remove(ctx->chunked_filter, 1);
}
ctx->finished = 1;
return SUCCESS;
}
static php_http_env_response_ops_t php_http_env_response_stream_ops = {
php_http_env_response_stream_init,
php_http_env_response_stream_dtor,
php_http_env_response_stream_get_status,
php_http_env_response_stream_set_status,
php_http_env_response_stream_set_protocol_version,
php_http_env_response_stream_set_header,
php_http_env_response_stream_add_header,
php_http_env_response_stream_del_header,
php_http_env_response_stream_write,
php_http_env_response_stream_flush,
php_http_env_response_stream_finish
};
php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void)
{
return &php_http_env_response_stream_ops;
}
#define PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj) \
do { \
if (!obj->message) { \
obj->message = php_http_message_init_env(NULL, PHP_HTTP_RESPONSE); \
} \
} while (0)
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___construct, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, __construct)
{
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_expect(obj->message = php_http_message_init_env(obj->message, PHP_HTTP_RESPONSE), unexpected_val, return);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse___invoke, 0, 0, 1)
ZEND_ARG_INFO(0, ob_string)
ZEND_ARG_INFO(0, ob_flags)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, __invoke)
{
char *ob_str;
size_t ob_len;
zend_long ob_flags = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &ob_str, &ob_len, &ob_flags)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_ENV_RESPONSE_OBJECT_INIT(obj);
if (!obj->body) {
php_http_message_object_init_body_object(obj);
}
if (ob_flags & PHP_OUTPUT_HANDLER_CLEAN) {
php_stream_truncate_set_size(php_http_message_body_stream(obj->message->body), 0);
} else {
php_http_message_body_append(obj->message->body, ob_str, ob_len);
}
RETURN_TRUE;
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEnvRequest, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, env_request, http\\Message, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setEnvRequest)
{
zval *env_req = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|O", &env_req, php_http_message_get_class_entry()), invalid_arg, return);
set_option(getThis(), ZEND_STRL("request"), IS_OBJECT, env_req, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentType, 0, 0, 1)
ZEND_ARG_INFO(0, content_type)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setContentType)
{
char *ct_str = NULL;
size_t ct_len = 0;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &ct_str, &ct_len), invalid_arg, return);
set_option(getThis(), ZEND_STRL("contentType"), IS_STRING, ct_str, ct_len);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentDisposition, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, disposition_params, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setContentDisposition)
{
zval *zdisposition;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a", &zdisposition), invalid_arg, return);
zend_update_property(Z_OBJCE_P(getThis()), getThis(), ZEND_STRL("contentDisposition"), zdisposition);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setContentEncoding, 0, 0, 1)
ZEND_ARG_INFO(0, content_encoding)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setContentEncoding)
{
zend_long ce;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ce), invalid_arg, return);
set_option(getThis(), ZEND_STRL("contentEncoding"), IS_LONG, &ce, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCacheControl, 0, 0, 1)
ZEND_ARG_INFO(0, cache_control)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setCacheControl)
{
char *cc_str = NULL;
size_t cc_len = 0;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &cc_str, &cc_len), invalid_arg, return);
set_option(getThis(), ZEND_STRL("cacheControl"), IS_STRING, cc_str, cc_len);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setLastModified, 0, 0, 1)
ZEND_ARG_INFO(0, last_modified)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setLastModified)
{
zend_long last_modified;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &last_modified), invalid_arg, return);
set_option(getThis(), ZEND_STRL("lastModified"), IS_LONG, &last_modified, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByLastModified, 0, 0, 0)
ZEND_ARG_INFO(0, header_name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, isCachedByLastModified)
{
char *header_name_str = NULL;
size_t header_name_len = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
if (!header_name_str || !header_name_len) {
header_name_str = "If-Modified-Since";
header_name_len = lenof("If-Modified-Since");
}
RETURN_LONG(php_http_env_is_response_cached_by_last_modified(getThis(), header_name_str, header_name_len, get_request(getThis())));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setEtag, 0, 0, 1)
ZEND_ARG_INFO(0, etag)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setEtag)
{
char *etag_str = NULL;
size_t etag_len = 0;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s!", &etag_str, &etag_len), invalid_arg, return);
set_option(getThis(), ZEND_STRL("etag"), IS_STRING, etag_str, etag_len);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_isCachedByEtag, 0, 0, 0)
ZEND_ARG_INFO(0, header_name)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, isCachedByEtag)
{
char *header_name_str = NULL;
size_t header_name_len = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &header_name_str, &header_name_len)) {
if (!header_name_str || !header_name_len) {
header_name_str = "If-None-Match";
header_name_len = lenof("If-None-Match");
}
RETURN_LONG(php_http_env_is_response_cached_by_etag(getThis(), header_name_str, header_name_len, get_request(getThis())));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setThrottleRate, 0, 0, 1)
ZEND_ARG_INFO(0, chunk_size)
ZEND_ARG_INFO(0, delay)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setThrottleRate)
{
zend_long chunk_size;
double delay = 1;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|d", &chunk_size, &delay), invalid_arg, return);
set_option(getThis(), ZEND_STRL("throttleDelay"), IS_DOUBLE, &delay, 0);
set_option(getThis(), ZEND_STRL("throttleChunk"), IS_LONG, &chunk_size, 0);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_setCookie, 0, 0, 1)
ZEND_ARG_INFO(0, cookie)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, setCookie)
{
zval *zcookie_new, tmp;
zend_string *zs;
zend_error_handling zeh;
php_http_cookie_list_t *list = NULL;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zcookie_new), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh);
switch (Z_TYPE_P(zcookie_new)) {
case IS_OBJECT:
if (instanceof_function(Z_OBJCE_P(zcookie_new), php_http_cookie_get_class_entry())) {
Z_ADDREF_P(zcookie_new);
break;
}
/* no break */
case IS_ARRAY:
list = php_http_cookie_list_from_struct(NULL, zcookie_new);
zcookie_new = &tmp;
ZVAL_OBJECT(zcookie_new, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo, 0);
break;
default:
zs = zval_get_string(zcookie_new);
list = php_http_cookie_list_parse(NULL, zs->val, zs->len, 0, NULL);
zend_string_release(zs);
zcookie_new = &tmp;
ZVAL_OBJECT(zcookie_new, &php_http_cookie_object_new_ex(php_http_cookie_get_class_entry(), list)->zo, 0);
}
zend_restore_error_handling(&zeh);
set_cookie(getThis(), zcookie_new);
zval_ptr_dtor(zcookie_new);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpEnvResponse_send, 0, 0, 0)
ZEND_ARG_INFO(0, stream)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpEnvResponse, send)
{
zval *zstream = NULL;
php_stream *s = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &zstream)) {
/* first flush the output layer to avoid conflicting headers and output;
* also, ob_start($thisEnvResponse) might have been called */
php_output_end_all();
if (zstream) {
php_http_env_response_t *r;
php_stream_from_zval(s, zstream);
r = php_http_env_response_init(NULL, getThis(), php_http_env_response_get_stream_ops(), s);
if (!r) {
RETURN_FALSE;
}
RETVAL_BOOL(SUCCESS == php_http_env_response_send(r));
php_http_env_response_free(&r);
} else {
php_http_env_response_t r;
if (!php_http_env_response_init(&r, getThis(), NULL, NULL)) {
RETURN_FALSE;
}
RETVAL_BOOL(SUCCESS == php_http_env_response_send(&r));
php_http_env_response_dtor(&r);
}
}
}
static zend_function_entry php_http_env_response_methods[] = {
PHP_ME(HttpEnvResponse, __construct, ai_HttpEnvResponse___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpEnvResponse, __invoke, ai_HttpEnvResponse___invoke, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setEnvRequest, ai_HttpEnvResponse_setEnvRequest, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setCookie, ai_HttpEnvResponse_setCookie, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setContentType, ai_HttpEnvResponse_setContentType, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setContentDisposition, ai_HttpEnvResponse_setContentDisposition, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setContentEncoding, ai_HttpEnvResponse_setContentEncoding, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setCacheControl, ai_HttpEnvResponse_setCacheControl, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setLastModified, ai_HttpEnvResponse_setLastModified, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, isCachedByLastModified, ai_HttpEnvResponse_isCachedByLastModified, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setEtag, ai_HttpEnvResponse_setEtag, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, isCachedByEtag, ai_HttpEnvResponse_isCachedByEtag, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, setThrottleRate, ai_HttpEnvResponse_setThrottleRate, ZEND_ACC_PUBLIC)
PHP_ME(HttpEnvResponse, send, ai_HttpEnvResponse_send, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
static zend_class_entry *php_http_env_response_class_entry;
zend_class_entry *php_http_get_env_response_class_entry(void)
{
return php_http_env_response_class_entry;
}
PHP_MINIT_FUNCTION(http_env_response)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Response", php_http_env_response_methods);
php_http_env_response_class_entry = zend_register_internal_class_ex(&ce, php_http_message_get_class_entry());
zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_NONE"), PHP_HTTP_CONTENT_ENCODING_NONE);
zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CONTENT_ENCODING_GZIP"), PHP_HTTP_CONTENT_ENCODING_GZIP);
zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_NO"), PHP_HTTP_CACHE_NO);
zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_HIT"), PHP_HTTP_CACHE_HIT);
zend_declare_class_constant_long(php_http_env_response_class_entry, ZEND_STRL("CACHE_MISS"), PHP_HTTP_CACHE_MISS);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("request"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cookies"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentType"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentDisposition"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("contentEncoding"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("cacheControl"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("etag"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("lastModified"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleDelay"), ZEND_ACC_PROTECTED);
zend_declare_property_null(php_http_env_response_class_entry, ZEND_STRL("throttleChunk"), ZEND_ACC_PROTECTED);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_env_response.h 0000644 0001750 0000144 00000006340 12667772426 017743 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_ENV_RESPONSE_H
#define PHP_HTTP_ENV_RESPONSE_H
typedef struct php_http_env_response php_http_env_response_t;
typedef struct php_http_env_response_ops {
ZEND_RESULT_CODE (*init)(php_http_env_response_t *r, void *arg);
void (*dtor)(php_http_env_response_t *r);
long (*get_status)(php_http_env_response_t *r);
ZEND_RESULT_CODE (*set_status)(php_http_env_response_t *r, long http_code);
ZEND_RESULT_CODE (*set_protocol_version)(php_http_env_response_t *r, php_http_version_t *v);
ZEND_RESULT_CODE (*set_header)(php_http_env_response_t *r, const char *fmt, ...);
ZEND_RESULT_CODE (*add_header)(php_http_env_response_t *r, const char *fmt, ...);
ZEND_RESULT_CODE (*del_header)(php_http_env_response_t *r, const char *header_str, size_t header_len);
ZEND_RESULT_CODE (*write)(php_http_env_response_t *r, const char *data_str, size_t data_len);
ZEND_RESULT_CODE (*flush)(php_http_env_response_t *r);
ZEND_RESULT_CODE (*finish)(php_http_env_response_t *r);
} php_http_env_response_ops_t;
PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_sapi_ops(void);
PHP_HTTP_API php_http_env_response_ops_t *php_http_env_response_get_stream_ops(void);
struct php_http_env_response {
void *ctx;
php_http_env_response_ops_t *ops;
php_http_cookie_list_t *cookies;
php_http_buffer_t *buffer;
zval options;
struct {
size_t chunk;
double delay;
} throttle;
struct {
php_http_range_status_t status;
HashTable values;
char boundary[32];
} range;
struct {
size_t length;
char *type;
char *encoding;
php_http_encoding_stream_t *encoder;
} content;
zend_bool done;
};
PHP_HTTP_API php_http_env_response_t *php_http_env_response_init(php_http_env_response_t *r, zval *options, php_http_env_response_ops_t *ops, void *ops_ctx);
PHP_HTTP_API ZEND_RESULT_CODE php_http_env_response_send(php_http_env_response_t *r);
PHP_HTTP_API void php_http_env_response_dtor(php_http_env_response_t *r);
PHP_HTTP_API void php_http_env_response_free(php_http_env_response_t **r);
PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zval *options, const char *header_str, size_t header_len, php_http_message_t *request);
PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_last_modified(zval *options, const char *header_str, size_t header_len, php_http_message_t *request);
PHP_HTTP_API zend_class_entry *php_http_get_env_response_class_entry();
PHP_MINIT_FUNCTION(http_env_response);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_etag.c 0000644 0001750 0000144 00000006667 12667772426 016164 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#ifdef PHP_HTTP_HAVE_HASH
# include "php_hash.h"
#endif
#include
#include
#include
php_http_etag_t *php_http_etag_init(const char *mode)
{
void *ctx;
php_http_etag_t *e;
if (mode && (!strcasecmp(mode, "crc32b"))) {
ctx = emalloc(sizeof(uint));
*((uint *) ctx) = ~0;
} else if (mode && !strcasecmp(mode, "sha1")) {
PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX)));
} else if (mode && !strcasecmp(mode, "md5")) {
PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX)));
} else {
#ifdef PHP_HTTP_HAVE_HASH
const php_hash_ops *eho = NULL;
if (mode && (eho = php_hash_fetch_ops(mode, strlen(mode)))) {
ctx = emalloc(eho->context_size);
eho->hash_init(ctx);
} else
#endif
return NULL;
}
e = emalloc(sizeof(*e));
e->ctx = ctx;
e->mode = estrdup(mode);
return e;
}
char *php_http_etag_finish(php_http_etag_t *e)
{
unsigned char digest[128] = {0};
char *etag = NULL;
if (!strcasecmp(e->mode, "crc32b")) {
unsigned char buf[4];
*((uint *) e->ctx) = ~*((uint *) e->ctx);
#ifdef WORDS_BIGENDIAN
etag = php_http_etag_digest((unsigned char *) e->ctx, 4);
#else
buf[0] = ((unsigned char *) e->ctx)[3];
buf[1] = ((unsigned char *) e->ctx)[2];
buf[2] = ((unsigned char *) e->ctx)[1];
buf[3] = ((unsigned char *) e->ctx)[0];
etag = php_http_etag_digest(buf, 4);
#endif
} else if ((!strcasecmp(e->mode, "sha1"))) {
PHP_SHA1Final(digest, e->ctx);
etag = php_http_etag_digest(digest, 20);
} else if ((!strcasecmp(e->mode, "md5"))) {
PHP_MD5Final(digest, e->ctx);
etag = php_http_etag_digest(digest, 16);
} else {
#ifdef PHP_HTTP_HAVE_HASH
const php_hash_ops *eho = NULL;
if (e->mode && (eho = php_hash_fetch_ops(e->mode, strlen(e->mode)))) {
eho->hash_final(digest, e->ctx);
etag = php_http_etag_digest(digest, eho->digest_size);
}
#endif
}
efree(e->ctx);
efree(e->mode);
efree(e);
return etag;
}
size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len)
{
if (!strcasecmp(e->mode, "crc32b")) {
uint i, c = *((uint *) e->ctx);
for (i = 0; i < data_len; ++i) {
CRC32(c, data_ptr[i]);
}
*((uint *) e->ctx) = c;
} else if ((!strcasecmp(e->mode, "sha1"))) {
PHP_SHA1Update(e->ctx, (const unsigned char *) data_ptr, data_len);
} else if ((!strcasecmp(e->mode, "md5"))) {
PHP_MD5Update(e->ctx, (const unsigned char *) data_ptr, data_len);
} else {
#ifdef PHP_HTTP_HAVE_HASH
const php_hash_ops *eho = NULL;
if (e->mode && (eho = php_hash_fetch_ops(e->mode, strlen(e->mode)))) {
eho->hash_update(e->ctx, (const unsigned char *) data_ptr, data_len);
}
#endif
}
return data_len;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_etag.h 0000644 0001750 0000144 00000003007 12667772426 016152 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_ETAG_H
#define PHP_HTTP_ETAG_H
typedef struct php_http_etag {
void *ctx;
char *mode;
} php_http_etag_t;
PHP_HTTP_API php_http_etag_t *php_http_etag_init(const char *mode);
PHP_HTTP_API size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len);
PHP_HTTP_API char *php_http_etag_finish(php_http_etag_t *e);
static inline char *php_http_etag_digest(const unsigned char *digest, int len)
{
static const char hexdigits[17] = "0123456789abcdef";
int i;
char *hex = emalloc(len * 2 + 1);
char *ptr = hex;
for (i = 0; i < len; ++i) {
*ptr++ = hexdigits[digest[i] >> 4];
*ptr++ = hexdigits[digest[i] & 0xF];
}
*ptr = '\0';
return hex;
}
#endif /* PHP_HTTP_ETAG_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_exception.c 0000644 0001750 0000144 00000014455 12667772426 017234 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
#ifndef PHP_HTTP_DBG_EXCEPTIONS
# define PHP_HTTP_DBG_EXCEPTIONS 0
#endif
#if PHP_HTTP_DBG_EXCEPTIONS
static void php_http_exception_hook(zval *ex)
{
if (ex) {
zval *m = zend_read_property(Z_OBJCE_P(ex), ex, "message", lenof("message"), 0);
fprintf(stderr, "*** Threw exception '%s'\n", Z_STRVAL_P(m));
} else {
fprintf(stderr, "*** Threw NULL exception\n");
}
}
#endif
static zend_class_entry *php_http_exception_interface_class_entry;
zend_class_entry *php_http_get_exception_interface_class_entry(void)
{
return php_http_exception_interface_class_entry;
}
static zend_class_entry *php_http_exception_runtime_class_entry;
zend_class_entry *php_http_get_exception_runtime_class_entry(void)
{
return php_http_exception_runtime_class_entry;
}
static zend_class_entry *php_http_exception_unexpected_val_class_entry;
zend_class_entry *php_http_get_exception_unexpected_val_class_entry(void)
{
return php_http_exception_unexpected_val_class_entry;
}
static zend_class_entry *php_http_exception_bad_method_call_class_entry;
zend_class_entry *php_http_get_exception_bad_method_call_class_entry(void)
{
return php_http_exception_bad_method_call_class_entry;
}
static zend_class_entry *php_http_exception_invalid_arg_class_entry;
zend_class_entry *php_http_get_exception_invalid_arg_class_entry(void)
{
return php_http_exception_invalid_arg_class_entry;
}
static zend_class_entry *php_http_exception_bad_header_class_entry;
zend_class_entry *php_http_get_exception_bad_header_class_entry(void)
{
return php_http_exception_bad_header_class_entry;
}
static zend_class_entry *php_http_exception_bad_url_class_entry;
zend_class_entry *php_http_get_exception_bad_url_class_entry(void)
{
return php_http_exception_bad_url_class_entry;
}
static zend_class_entry *php_http_exception_bad_message_class_entry;
zend_class_entry *php_http_get_exception_bad_message_class_entry(void)
{
return php_http_exception_bad_message_class_entry;
}
static zend_class_entry *php_http_exception_bad_conversion_class_entry;
zend_class_entry *php_http_get_exception_bad_conversion_class_entry(void)
{
return php_http_exception_bad_conversion_class_entry;
}
static zend_class_entry *php_http_exception_bad_querystring_class_entry;
zend_class_entry *php_http_get_exception_bad_querystring_class_entry(void)
{
return php_http_exception_bad_querystring_class_entry;
}
PHP_MINIT_FUNCTION(http_exception)
{
zend_class_entry *cep, ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Exception", NULL);
php_http_exception_interface_class_entry = zend_register_internal_interface(&ce);
/*
* Would be great to only have a few exceptions and rather more identifying
* error codes, but zend_replace_error_handling() does not accept any codes.
*/
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "RuntimeException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_RuntimeException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_runtime_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "UnexpectedValueException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_UnexpectedValueException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_unexpected_val_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMethodCallException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_BadMethodCallException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_method_call_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "InvalidArgumentException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_InvalidArgumentException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_invalid_arg_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadHeaderException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_header_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadUrlException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_url_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadMessageException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_message_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadConversionException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_conversion_class_entry = cep;
memset(&ce, 0, sizeof(ce));
INIT_NS_CLASS_ENTRY(ce, "http\\Exception", "BadQueryStringException", NULL);
cep = zend_register_internal_class_ex(&ce, spl_ce_DomainException);
zend_class_implements(cep, 1, php_http_exception_interface_class_entry);
php_http_exception_bad_querystring_class_entry = cep;
#if PHP_HTTP_DBG_EXCEPTIONS
zend_throw_exception_hook = php_http_exception_hook;
#endif
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_exception.h 0000644 0001750 0000144 00000004412 12667772426 017231 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_EXCEPTION_H
#define PHP_HTTP_EXCEPTION_H
/* short hand for zend_throw_exception_ex */
#define php_http_throw(e, fmt, ...) \
zend_throw_exception_ex(php_http_get_exception_ ##e## _class_entry(), 0, fmt, __VA_ARGS__)
/* wrap a call with replaced zend_error_handling */
#define php_http_expect(test, e, fail) \
do { \
zend_error_handling __zeh; \
zend_replace_error_handling(EH_THROW, php_http_get_exception_ ##e## _class_entry(), &__zeh); \
if (!(test)) { \
zend_restore_error_handling(&__zeh); \
fail; \
} \
zend_restore_error_handling(&__zeh); \
} while(0)
PHP_HTTP_API zend_class_entry *php_http_get_exception_interface_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_runtime_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_unexpected_val_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_method_call_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_invalid_arg_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_header_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_url_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_message_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_conversion_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_exception_bad_querystring_class_entry(void);
PHP_MINIT_FUNCTION(http_exception);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_filter.c 0000644 0001750 0000144 00000027345 12667772426 016525 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#ifndef DBG_FILTER
# define DBG_FILTER 0
#endif
PHP_MINIT_FUNCTION(http_filter)
{
php_stream_filter_register_factory("http.*", &php_http_filter_factory);
return SUCCESS;
}
#define PHP_HTTP_FILTER_PARAMS \
php_stream *stream, \
php_stream_filter *this, \
php_stream_bucket_brigade *buckets_in, \
php_stream_bucket_brigade *buckets_out, \
size_t *bytes_consumed, \
int flags
#define PHP_HTTP_FILTER_OP(filter) \
http_filter_op_ ##filter
#define PHP_HTTP_FILTER_OPS(filter) \
php_stream_filter_ops PHP_HTTP_FILTER_OP(filter)
#define PHP_HTTP_FILTER_DTOR(filter) \
http_filter_ ##filter## _dtor
#define PHP_HTTP_FILTER_DESTRUCTOR(filter) \
void PHP_HTTP_FILTER_DTOR(filter)(php_stream_filter *this)
#define PHP_HTTP_FILTER_FUNC(filter) \
http_filter_ ##filter
#define PHP_HTTP_FILTER_FUNCTION(filter) \
php_stream_filter_status_t PHP_HTTP_FILTER_FUNC(filter)(PHP_HTTP_FILTER_PARAMS)
#define PHP_HTTP_FILTER_BUFFER(filter) \
http_filter_ ##filter## _buffer
#define PHP_HTTP_FILTER_IS_CLOSING(stream, flags) \
( (flags & PSFS_FLAG_FLUSH_CLOSE) \
|| php_stream_eof(stream) \
|| ((stream->ops == &php_stream_temp_ops || stream->ops == &php_stream_memory_ops) && stream->eof) \
)
#define NEW_BUCKET(data, length) \
{ \
char *__data; \
php_stream_bucket *__buck; \
\
__data = pemalloc(length, this->is_persistent); \
if (!__data) { \
return PSFS_ERR_FATAL; \
} \
memcpy(__data, data, length); \
\
__buck = php_stream_bucket_new(stream, __data, length, 1, this->is_persistent); \
if (!__buck) { \
pefree(__data, this->is_persistent); \
return PSFS_ERR_FATAL; \
} \
\
php_stream_bucket_append(buckets_out, __buck); \
}
typedef struct _http_chunked_decode_filter_buffer_t {
php_http_buffer_t buffer;
ulong hexlen;
} PHP_HTTP_FILTER_BUFFER(chunked_decode);
typedef php_http_encoding_stream_t PHP_HTTP_FILTER_BUFFER(zlib);
static PHP_HTTP_FILTER_FUNCTION(chunked_decode)
{
int out_avail = 0;
php_stream_bucket *ptr, *nxt;
PHP_HTTP_FILTER_BUFFER(chunked_decode) *buffer = Z_PTR(this->abstract);
if (bytes_consumed) {
*bytes_consumed = 0;
}
/* fetch available bucket data */
for (ptr = buckets_in->head; ptr; ptr = nxt) {
if (bytes_consumed) {
*bytes_consumed += ptr->buflen;
}
if (PHP_HTTP_BUFFER_NOMEM == php_http_buffer_append(PHP_HTTP_BUFFER(buffer), ptr->buf, ptr->buflen)) {
return PSFS_ERR_FATAL;
}
nxt = ptr->next;
php_stream_bucket_unlink(ptr);
php_stream_bucket_delref(ptr);
}
if (!php_http_buffer_fix(PHP_HTTP_BUFFER(buffer))) {
return PSFS_ERR_FATAL;
}
/* we have data in our buffer */
while (PHP_HTTP_BUFFER(buffer)->used) {
/* we already know the size of the chunk and are waiting for data */
if (buffer->hexlen) {
/* not enough data buffered */
if (PHP_HTTP_BUFFER(buffer)->used < buffer->hexlen) {
/* flush anyway? */
if (flags & PSFS_FLAG_FLUSH_INC) {
/* flush all data (should only be chunk data) */
out_avail = 1;
NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used);
/* waiting for less data now */
buffer->hexlen -= PHP_HTTP_BUFFER(buffer)->used;
/* no more buffered data */
php_http_buffer_reset(PHP_HTTP_BUFFER(buffer));
/* break */
}
/* we have too less data and don't need to flush */
else {
break;
}
}
/* we seem to have all data of the chunk */
else {
out_avail = 1;
NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, buffer->hexlen);
/* remove outgoing data from the buffer */
php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, buffer->hexlen);
/* reset hexlen */
buffer->hexlen = 0;
/* continue */
}
}
/* we don't know the length of the chunk yet */
else {
size_t off = 0;
/* ignore preceeding CRLFs (too loose?) */
while (off < PHP_HTTP_BUFFER(buffer)->used && (
PHP_HTTP_BUFFER(buffer)->data[off] == '\n' ||
PHP_HTTP_BUFFER(buffer)->data[off] == '\r')) {
++off;
}
if (off) {
php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, off);
}
/* still data there? */
if (PHP_HTTP_BUFFER(buffer)->used) {
int eollen;
const char *eolstr;
/* we need eol, so we can be sure we have all hex digits */
php_http_buffer_fix(PHP_HTTP_BUFFER(buffer));
if ((eolstr = php_http_locate_bin_eol(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used, &eollen))) {
char *stop = NULL;
/* read in chunk size */
buffer->hexlen = strtoul(PHP_HTTP_BUFFER(buffer)->data, &stop, 16);
/* if strtoul() stops at the beginning of the buffered data
there's something oddly wrong, i.e. bad input */
if (stop == PHP_HTTP_BUFFER(buffer)->data) {
return PSFS_ERR_FATAL;
}
/* cut out */
php_http_buffer_cut(PHP_HTTP_BUFFER(buffer), 0, eolstr + eollen - PHP_HTTP_BUFFER(buffer)->data);
/* buffer->hexlen is 0 now or contains the size of the next chunk */
if (!buffer->hexlen) {
php_stream_notify_info(PHP_STREAM_CONTEXT(stream), PHP_STREAM_NOTIFY_COMPLETED, NULL, 0);
break;
}
/* continue */
} else {
/* we have not enough data buffered to read in chunk size */
break;
}
}
/* break */
}
}
/* flush before close, but only if we are already waiting for more data */
if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags) && buffer->hexlen && PHP_HTTP_BUFFER(buffer)->used) {
out_avail = 1;
NEW_BUCKET(PHP_HTTP_BUFFER(buffer)->data, PHP_HTTP_BUFFER(buffer)->used);
php_http_buffer_reset(PHP_HTTP_BUFFER(buffer));
buffer->hexlen = 0;
}
return out_avail ? PSFS_PASS_ON : PSFS_FEED_ME;
}
static PHP_HTTP_FILTER_DESTRUCTOR(chunked_decode)
{
PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = Z_PTR(this->abstract);
php_http_buffer_dtor(PHP_HTTP_BUFFER(b));
pefree(b, this->is_persistent);
}
static PHP_HTTP_FILTER_FUNCTION(chunked_encode)
{
php_http_buffer_t buf;
php_stream_bucket *ptr, *nxt;
if (bytes_consumed) {
*bytes_consumed = 0;
}
/* new data available? */
php_http_buffer_init(&buf);
/* fetch available bucket data */
for (ptr = buckets_in->head; ptr; ptr = nxt) {
if (bytes_consumed) {
*bytes_consumed += ptr->buflen;
}
#if DBG_FILTER
fprintf(stderr, "update: chunked (-> %zu) (w: %zu, r: %zu)\n", ptr->buflen, stream->writepos, stream->readpos);
#endif
nxt = ptr->next;
php_stream_bucket_unlink(ptr);
php_http_buffer_appendf(&buf, "%lx" PHP_HTTP_CRLF, (long unsigned int) ptr->buflen);
php_http_buffer_append(&buf, ptr->buf, ptr->buflen);
php_http_buffer_appends(&buf, PHP_HTTP_CRLF);
/* pass through */
NEW_BUCKET(buf.data, buf.used);
/* reset */
php_http_buffer_reset(&buf);
php_stream_bucket_delref(ptr);
}
/* free buffer */
php_http_buffer_dtor(&buf);
/* terminate with "0" */
if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) {
#if DBG_FILTER
fprintf(stderr, "finish: chunked\n");
#endif
NEW_BUCKET("0" PHP_HTTP_CRLF PHP_HTTP_CRLF, lenof("0" PHP_HTTP_CRLF PHP_HTTP_CRLF));
}
return PSFS_PASS_ON;
}
static PHP_HTTP_FILTER_OPS(chunked_decode) = {
PHP_HTTP_FILTER_FUNC(chunked_decode),
PHP_HTTP_FILTER_DTOR(chunked_decode),
"http.chunked_decode"
};
static PHP_HTTP_FILTER_OPS(chunked_encode) = {
PHP_HTTP_FILTER_FUNC(chunked_encode),
NULL,
"http.chunked_encode"
};
static PHP_HTTP_FILTER_FUNCTION(zlib)
{
php_stream_bucket *ptr, *nxt;
PHP_HTTP_FILTER_BUFFER(zlib) *buffer = Z_PTR(this->abstract);
if (bytes_consumed) {
*bytes_consumed = 0;
}
/* fetch available bucket data */
for (ptr = buckets_in->head; ptr; ptr = nxt) {
char *encoded = NULL;
size_t encoded_len = 0;
if (bytes_consumed) {
*bytes_consumed += ptr->buflen;
}
#if DBG_FILTER
fprintf(stderr, "bucket: b=%p p=%p p=%p\n", ptr->brigade, ptr->prev, ptr->next);
#endif
nxt = ptr->next;
php_stream_bucket_unlink(ptr);
php_http_encoding_stream_update(buffer, ptr->buf, ptr->buflen, &encoded, &encoded_len);
#if DBG_FILTER
fprintf(stderr, "update: deflate (-> %zu) (w: %zu, r: %zu)\n", encoded_len, stream->writepos, stream->readpos);
#endif
if (encoded) {
if (encoded_len) {
NEW_BUCKET(encoded, encoded_len);
}
efree(encoded);
}
php_stream_bucket_delref(ptr);
}
/* flush & close */
if (flags & PSFS_FLAG_FLUSH_INC) {
char *encoded = NULL;
size_t encoded_len = 0;
php_http_encoding_stream_flush(buffer, &encoded, &encoded_len);
#if DBG_FILTER
fprintf(stderr, "flush: deflate (-> %zu)\n", encoded_len);
#endif
if (encoded) {
if (encoded_len) {
NEW_BUCKET(encoded, encoded_len);
}
efree(encoded);
}
}
if (PHP_HTTP_FILTER_IS_CLOSING(stream, flags)) {
char *encoded = NULL;
size_t encoded_len = 0;
php_http_encoding_stream_finish(buffer, &encoded, &encoded_len);
#if DBG_FILTER
fprintf(stderr, "finish: deflate (-> %zu)\n", encoded_len);
#endif
if (encoded) {
if (encoded_len) {
NEW_BUCKET(encoded, encoded_len);
}
efree(encoded);
}
}
return PSFS_PASS_ON;
}
static PHP_HTTP_FILTER_DESTRUCTOR(zlib)
{
PHP_HTTP_FILTER_BUFFER(zlib) *buffer = Z_PTR(this->abstract);
php_http_encoding_stream_free(&buffer);
}
static PHP_HTTP_FILTER_OPS(deflate) = {
PHP_HTTP_FILTER_FUNC(zlib),
PHP_HTTP_FILTER_DTOR(zlib),
"http.deflate"
};
static PHP_HTTP_FILTER_OPS(inflate) = {
PHP_HTTP_FILTER_FUNC(zlib),
PHP_HTTP_FILTER_DTOR(zlib),
"http.inflate"
};
static php_stream_filter *http_filter_create(const char *name, zval *params, int p)
{
zval *tmp = params;
php_stream_filter *f = NULL;
int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0;
if (params) {
switch (Z_TYPE_P(params)) {
case IS_ARRAY:
case IS_OBJECT:
if (!(tmp = zend_hash_str_find_ind(HASH_OF(params), ZEND_STRL("flags")))) {
break;
}
/* no break */
default:
flags |= zval_get_long(tmp) & 0x0fffffff;
break;
}
}
if (!strcasecmp(name, "http.chunked_decode")) {
PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = NULL;
if ((b = pecalloc(1, sizeof(PHP_HTTP_FILTER_BUFFER(chunked_decode)), p))) {
php_http_buffer_init_ex(PHP_HTTP_BUFFER(b), 4096, p ? PHP_HTTP_BUFFER_INIT_PERSISTENT : 0);
if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_decode), b, p))) {
pefree(b, p);
}
}
} else
if (!strcasecmp(name, "http.chunked_encode")) {
f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(chunked_encode), NULL, p);
} else
if (!strcasecmp(name, "http.inflate")) {
PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags))) {
if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(inflate), b, p))) {
php_http_encoding_stream_free(&b);
}
}
} else
if (!strcasecmp(name, "http.deflate")) {
PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL;
if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags))) {
if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) {
php_http_encoding_stream_free(&b);
}
}
}
return f;
}
php_stream_filter_factory php_http_filter_factory = {
http_filter_create
};
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_filter.h 0000644 0001750 0000144 00000001722 12667772426 016521 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_FILTER_H
#define PHP_HTTP_FILTER_H
PHP_HTTP_API php_stream_filter_factory php_http_filter_factory;
PHP_MINIT_FUNCTION(http_filter);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_header_parser.c 0000644 0001750 0000144 00000042461 12667772426 020040 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#ifndef DBG_PARSER
# define DBG_PARSER 0
#endif
typedef struct php_http_header_parser_state_spec {
php_http_header_parser_state_t state;
unsigned need_data:1;
} php_http_header_parser_state_spec_t;
static const php_http_header_parser_state_spec_t php_http_header_parser_states[] = {
{PHP_HTTP_HEADER_PARSER_STATE_START, 1},
{PHP_HTTP_HEADER_PARSER_STATE_KEY, 1},
{PHP_HTTP_HEADER_PARSER_STATE_VALUE, 1},
{PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX, 0},
{PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE, 0},
{PHP_HTTP_HEADER_PARSER_STATE_DONE, 0}
};
php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser)
{
if (!parser) {
parser = emalloc(sizeof(*parser));
}
memset(parser, 0, sizeof(*parser));
return parser;
}
php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...)
{
va_list va_args;
unsigned i;
php_http_header_parser_state_t state = 0;
/* short circuit */
ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc);
va_start(va_args, argc);
for (i = 0; i < argc; ++i) {
state = va_arg(va_args, php_http_header_parser_state_t);
zend_ptr_stack_push(&parser->stack, (void *) state);
}
va_end(va_args);
return state;
}
php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser)
{
if (parser->stack.top) {
return (php_http_header_parser_state_t) parser->stack.elements[parser->stack.top - 1];
}
return PHP_HTTP_HEADER_PARSER_STATE_START;
}
php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser)
{
if (parser->stack.top) {
return (php_http_header_parser_state_t) zend_ptr_stack_pop(&parser->stack);
}
return PHP_HTTP_HEADER_PARSER_STATE_START;
}
void php_http_header_parser_dtor(php_http_header_parser_t *parser)
{
zend_ptr_stack_destroy(&parser->stack);
php_http_info_dtor(&parser->info);
PTR_FREE(parser->_key.str);
PTR_FREE(parser->_val.str);
}
void php_http_header_parser_free(php_http_header_parser_t **parser)
{
if (*parser) {
php_http_header_parser_dtor(*parser);
efree(*parser);
*parser = NULL;
}
}
/* NOTE: 'str' has to be null terminated */
static void php_http_header_parser_error(size_t valid_len, char *str, size_t len, const char *eol_str )
{
zend_string *escaped_str = zend_string_init(str, len, 0);
escaped_str = php_addcslashes(escaped_str, 1, ZEND_STRL("\x0..\x1F\x7F..\xFF"));
if (valid_len != len && (!eol_str || (str+valid_len) != eol_str)) {
php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected character '\\%03o' at pos %zu of '%s'", str[valid_len], valid_len, escaped_str->val);
} else if (eol_str) {
php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of line at pos %zu of '%s'", eol_str - str, escaped_str->val);
} else {
php_error_docref(NULL, E_WARNING, "Failed to parse headers: unexpected end of input at pos %zu of '%s'", len, escaped_str->val);
}
efree(escaped_str);
}
php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
{
while (buffer->used || !php_http_header_parser_states[php_http_header_parser_state_is(parser)].need_data) {
#if DBG_PARSER
const char *state[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"};
fprintf(stderr, "#HP: %s (avail:%zu, num:%d cleanup:%u)\n", php_http_header_parser_state_is(parser) < 0 ? "FAILURE" : state[php_http_header_parser_state_is(parser)], buffer->used, headers?zend_hash_num_elements(headers):0, flags);
_dpf(0, buffer->data, buffer->used);
#endif
switch (php_http_header_parser_state_pop(parser)) {
case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
php_error_docref(NULL, E_WARNING, "Failed to parse headers");
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
case PHP_HTTP_HEADER_PARSER_STATE_START: {
char *ptr = buffer->data;
while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
++ptr;
}
php_http_buffer_cut(buffer, 0, ptr - buffer->data);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
break;
}
case PHP_HTTP_HEADER_PARSER_STATE_KEY: {
const char *colon, *eol_str = NULL;
int eol_len = 0;
/* fix buffer here, so eol_str pointer doesn't become obsolete afterwards */
php_http_buffer_fix(buffer);
if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
/* end of headers */
php_http_buffer_cut(buffer, 0, eol_len);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_DONE);
} else if (php_http_info_parse(&parser->info, buffer->data)) {
/* new message starting with request/response line */
if (callback_func) {
callback_func(callback_arg, &headers, &parser->info);
}
php_http_info_dtor(&parser->info);
php_http_buffer_cut(buffer, 0, eol_str + eol_len - buffer->data);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
} else if ((colon = memchr(buffer->data, ':', buffer->used)) && (!eol_str || eol_str > colon)) {
/* header: string */
size_t valid_len;
parser->_key.len = colon - buffer->data;
parser->_key.str = estrndup(buffer->data, parser->_key.len);
valid_len = strspn(parser->_key.str, PHP_HTTP_HEADER_NAME_CHARS);
if (valid_len != parser->_key.len) {
php_http_header_parser_error(valid_len, parser->_key.str, parser->_key.len, eol_str);
PTR_SET(parser->_key.str, NULL);
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
}
while (PHP_HTTP_IS_CTYPE(space, *++colon) && *colon != '\n' && *colon != '\r');
php_http_buffer_cut(buffer, 0, colon - buffer->data);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
} else if (eol_str || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) {
/* neither reqeust/response line nor 'header:' string, or injected new line or NUL etc. */
php_http_header_parser_error(strspn(buffer->data, PHP_HTTP_HEADER_NAME_CHARS), buffer->data, buffer->used, eol_str);
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
} else {
/* keep feeding */
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
}
break;
}
case PHP_HTTP_HEADER_PARSER_STATE_VALUE: {
const char *eol_str;
int eol_len;
#define SET_ADD_VAL(slen, eol_len) \
do { \
const char *ptr = buffer->data; \
size_t len = slen; \
\
while (len > 0 && PHP_HTTP_IS_CTYPE(space, *ptr)) { \
++ptr; \
--len; \
} \
while (len > 0 && PHP_HTTP_IS_CTYPE(space, ptr[len - 1])) { \
--len; \
} \
\
if (len > 0) { \
if (parser->_val.str) { \
parser->_val.str = erealloc(parser->_val.str, parser->_val.len + len + 2); \
parser->_val.str[parser->_val.len++] = ' '; \
memcpy(&parser->_val.str[parser->_val.len], ptr, len); \
parser->_val.len += len; \
parser->_val.str[parser->_val.len] = '\0'; \
} else { \
parser->_val.len = len; \
parser->_val.str = estrndup(ptr, len); \
} \
} \
php_http_buffer_cut(buffer, 0, slen + eol_len); \
} while (0)
if ((eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) {
SET_ADD_VAL(eol_str - buffer->data, eol_len);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
} else if (flags & PHP_HTTP_HEADER_PARSER_CLEANUP) {
if (buffer->used) {
SET_ADD_VAL(buffer->used, 0);
}
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
} else {
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
}
break;
}
case PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX:
if (buffer->used && (*buffer->data == ' ' || *buffer->data == '\t')) {
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE);
} else if (buffer->used || (flags & PHP_HTTP_HEADER_PARSER_CLEANUP)) {
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
} else {
/* keep feeding */
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
}
break;
case PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE:
if (parser->_key.str && parser->_val.str) {
zval tmp, *exist;
size_t valid_len = strlen(parser->_val.str);
/* check for truncation */
if (valid_len != parser->_val.len) {
php_http_header_parser_error(valid_len, parser->_val.str, parser->_val.len, NULL);
PTR_SET(parser->_key.str, NULL);
PTR_SET(parser->_val.str, NULL);
return php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
}
if (!headers && callback_func) {
callback_func(callback_arg, &headers, NULL);
}
php_http_pretty_key(parser->_key.str, parser->_key.len, 1, 1);
if ((exist = zend_symtable_str_find(headers, parser->_key.str, parser->_key.len))) {
convert_to_array(exist);
add_next_index_str(exist, php_http_cs2zs(parser->_val.str, parser->_val.len));
} else {
ZVAL_STR(&tmp, php_http_cs2zs(parser->_val.str, parser->_val.len));
zend_symtable_str_update(headers, parser->_key.str, parser->_key.len, &tmp);
}
parser->_val.str = NULL;
}
PTR_SET(parser->_key.str, NULL);
PTR_SET(parser->_val.str, NULL);
php_http_header_parser_state_push(parser, 1, PHP_HTTP_HEADER_PARSER_STATE_KEY);
break;
case PHP_HTTP_HEADER_PARSER_STATE_DONE:
return PHP_HTTP_HEADER_PARSER_STATE_DONE;
}
}
return php_http_header_parser_state_is(parser);
}
php_http_header_parser_state_t php_http_header_parser_parse_stream(php_http_header_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg)
{
php_http_header_parser_state_t state = PHP_HTTP_HEADER_PARSER_STATE_START;
if (!buf->data) {
php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
}
while (1) {
size_t justread = 0;
#if DBG_PARSER
const char *states[] = {"START", "KEY", "VALUE", "VALUE_EX", "HEADER_DONE", "DONE"};
fprintf(stderr, "#SHP: %s (f:%u)\n", states[state], flags);
#endif
/* resize if needed */
if (buf->free < 0x1000) {
php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
}
switch (state) {
case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
case PHP_HTTP_HEADER_PARSER_STATE_DONE:
return state;
default:
/* read line */
php_stream_get_line(s, buf->data + buf->used, buf->free, &justread);
/* if we fail reading a whole line, try a single char */
if (!justread) {
int c = php_stream_getc(s);
if (c != EOF) {
char s[1] = {c};
justread = php_http_buffer_append(buf, s, 1);
}
}
php_http_buffer_account(buf, justread);
}
if (justread) {
state = php_http_header_parser_parse(parser, buf, flags, headers, callback_func, callback_arg);
} else if (php_stream_eof(s)) {
return php_http_header_parser_parse(parser, buf, flags | PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_arg);
} else {
return state;
}
}
return PHP_HTTP_HEADER_PARSER_STATE_DONE;
}
static zend_class_entry *php_http_header_parser_class_entry;
zend_class_entry *php_http_get_header_parser_class_entry(void)
{
return php_http_header_parser_class_entry;
}
static zend_object_handlers php_http_header_parser_object_handlers;
zend_object *php_http_header_parser_object_new(zend_class_entry *ce)
{
return &php_http_header_parser_object_new_ex(ce, NULL)->zo;
}
php_http_header_parser_object_t *php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser)
{
php_http_header_parser_object_t *o;
o = ecalloc(1, sizeof(php_http_header_parser_object_t) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
if (parser) {
o->parser = parser;
} else {
o->parser = php_http_header_parser_init(NULL);
}
o->buffer = php_http_buffer_new();
o->zo.handlers = &php_http_header_parser_object_handlers;
return o;
}
void php_http_header_parser_object_free(zend_object *object)
{
php_http_header_parser_object_t *o = PHP_HTTP_OBJ(object, NULL);
if (o->parser) {
php_http_header_parser_free(&o->parser);
}
if (o->buffer) {
php_http_buffer_free(&o->buffer);
}
zend_object_std_dtor(object);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_getState, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpHeaderParser, getState)
{
php_http_header_parser_object_t *parser_obj = PHP_HTTP_OBJ(NULL, getThis());
zend_parse_parameters_none();
/* always return the real state */
RETVAL_LONG(php_http_header_parser_state_is(parser_obj->parser));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_parse, 0, 0, 3)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_ARRAY_INFO(1, headers, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpHeaderParser, parse)
{
php_http_header_parser_object_t *parser_obj;
zval *zmsg;
char *data_str;
size_t data_len;
zend_long flags;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return);
ZVAL_DEREF(zmsg);
if (Z_TYPE_P(zmsg) != IS_ARRAY) {
zval_dtor(zmsg);
array_init(zmsg);
}
parser_obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_buffer_append(parser_obj->buffer, data_str, data_len);
RETVAL_LONG(php_http_header_parser_parse(parser_obj->parser, parser_obj->buffer, flags, Z_ARRVAL_P(zmsg), NULL, NULL));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeaderParser_stream, 0, 0, 3)
ZEND_ARG_INFO(0, stream)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_ARRAY_INFO(1, headers, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpHeaderParser, stream)
{
php_http_header_parser_object_t *parser_obj;
zend_error_handling zeh;
zval *zmsg, *zstream;
php_stream *s;
zend_long flags;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zstream, &flags, &zmsg), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh);
php_stream_from_zval(s, zstream);
zend_restore_error_handling(&zeh);
ZVAL_DEREF(zmsg);
if (Z_TYPE_P(zmsg) != IS_ARRAY) {
zval_dtor(zmsg);
array_init(zmsg);
}
parser_obj = PHP_HTTP_OBJ(NULL, getThis());
RETVAL_LONG(php_http_header_parser_parse_stream(parser_obj->parser, parser_obj->buffer, s, flags, Z_ARRVAL_P(zmsg), NULL, NULL));
}
static zend_function_entry php_http_header_parser_methods[] = {
PHP_ME(HttpHeaderParser, getState, ai_HttpHeaderParser_getState, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeaderParser, parse, ai_HttpHeaderParser_parse, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeaderParser, stream, ai_HttpHeaderParser_stream, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(http_header_parser)
{
zend_class_entry ce;
INIT_NS_CLASS_ENTRY(ce, "http\\Header", "Parser", php_http_header_parser_methods);
php_http_header_parser_class_entry = zend_register_internal_class(&ce);
memcpy(&php_http_header_parser_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_header_parser_class_entry->create_object = php_http_header_parser_object_new;
php_http_header_parser_object_handlers.offset = XtOffsetOf(php_http_header_parser_object_t, zo);
php_http_header_parser_object_handlers.clone_obj = NULL;
php_http_header_parser_object_handlers.free_obj = php_http_header_parser_object_free;
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_HEADER_PARSER_CLEANUP);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_HEADER_PARSER_STATE_FAILURE);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_HEADER_PARSER_STATE_START);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_KEY"), PHP_HTTP_HEADER_PARSER_STATE_KEY);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE"), PHP_HTTP_HEADER_PARSER_STATE_VALUE);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_VALUE_EX"), PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE);
zend_declare_class_constant_long(php_http_header_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_HEADER_PARSER_STATE_DONE);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_header_parser.h 0000644 0001750 0000144 00000006212 12667772426 020037 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_HEADER_PARSER_H
#define PHP_HTTP_HEADER_PARSER_H
#include "php_http_info.h"
typedef enum php_http_header_parser_state {
PHP_HTTP_HEADER_PARSER_STATE_FAILURE = FAILURE,
PHP_HTTP_HEADER_PARSER_STATE_START = 0,
PHP_HTTP_HEADER_PARSER_STATE_KEY,
PHP_HTTP_HEADER_PARSER_STATE_VALUE,
PHP_HTTP_HEADER_PARSER_STATE_VALUE_EX,
PHP_HTTP_HEADER_PARSER_STATE_HEADER_DONE,
PHP_HTTP_HEADER_PARSER_STATE_DONE
} php_http_header_parser_state_t;
#define PHP_HTTP_HEADER_PARSER_CLEANUP 0x1
typedef struct php_http_header_parser {
zend_ptr_stack stack;
php_http_info_t info;
struct {
char *str;
size_t len;
} _key;
struct {
char *str;
size_t len;
} _val;
} php_http_header_parser_t;
PHP_HTTP_API php_http_header_parser_t *php_http_header_parser_init(php_http_header_parser_t *parser);
PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_push(php_http_header_parser_t *parser, unsigned argc, ...);
PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_is(php_http_header_parser_t *parser);
PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_state_pop(php_http_header_parser_t *parser);
PHP_HTTP_API void php_http_header_parser_dtor(php_http_header_parser_t *parser);
PHP_HTTP_API void php_http_header_parser_free(php_http_header_parser_t **parser);
PHP_HTTP_API php_http_header_parser_state_t php_http_header_parser_parse(php_http_header_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg);
PHP_HTTP_API php_http_header_parser_state_t php_http_headerparser_parse_stream(php_http_header_parser_t *parser, php_http_buffer_t *buffer, php_stream *s, unsigned flags, HashTable *headers, php_http_info_callback_t callback_func, void *callback_arg);
typedef struct php_http_header_parser_object {
php_http_buffer_t *buffer;
php_http_header_parser_t *parser;
zend_object zo;
} php_http_header_parser_object_t;
PHP_HTTP_API zend_class_entry *php_http_get_header_parser_class_entry(void);
PHP_MINIT_FUNCTION(http_header_parser);
zend_object *php_http_header_parser_object_new(zend_class_entry *ce);
php_http_header_parser_object_t *php_http_header_parser_object_new_ex(zend_class_entry *ce, php_http_header_parser_t *parser);
void php_http_header_parser_object_free(zend_object *object);
#endif /* PHP_HTTP_HEADER_PARSER_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_header.c 0000644 0001750 0000144 00000030622 12667772426 016460 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data)
{
php_http_header_parser_t ctx;
php_http_buffer_t buf;
php_http_header_parser_state_t rs;
if (!php_http_buffer_from_string_ex(&buf, header, length)) {
php_error_docref(NULL, E_WARNING, "Could not allocate buffer");
return FAILURE;
}
if (!php_http_header_parser_init(&ctx)) {
php_http_buffer_dtor(&buf);
php_error_docref(NULL, E_WARNING, "Could not initialize header parser");
return FAILURE;
}
rs = php_http_header_parser_parse(&ctx, &buf, PHP_HTTP_HEADER_PARSER_CLEANUP, headers, callback_func, callback_data);
php_http_header_parser_dtor(&ctx);
php_http_buffer_dtor(&buf);
return rs == PHP_HTTP_HEADER_PARSER_STATE_FAILURE ? FAILURE : SUCCESS;
}
void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg)
{
php_http_arrkey_t key;
zval *header, *single_header;
ZEND_HASH_FOREACH_KEY_VAL(headers, key.h, key.key, header)
{
if (key.key) {
if (zend_string_equals_literal(key.key, "Set-Cookie") && Z_TYPE_P(header) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), single_header)
{
if (Z_TYPE_P(single_header) == IS_ARRAY) {
php_http_cookie_list_t *cookie = php_http_cookie_list_from_struct(NULL, single_header);
if (cookie) {
char *buf;
size_t len;
php_http_cookie_list_to_string(cookie, &buf, &len);
cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", buf);
php_http_cookie_list_free(&cookie);
efree(buf);
}
} else {
zend_string *zs = php_http_header_value_to_string(single_header);
cb(cb_arg, crlf ? "Set-Cookie: %s" PHP_HTTP_CRLF : "Set-Cookie: %s", zs->val);
zend_string_release(zs);
}
}
ZEND_HASH_FOREACH_END();
} else {
zend_string *zs = php_http_header_value_to_string(header);
cb(cb_arg, crlf ? "%s: %s" PHP_HTTP_CRLF : "%s: %s", key.key->val, zs->val);
zend_string_release(zs);
}
}
}
ZEND_HASH_FOREACH_END();
}
void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers)
{
php_http_header_to_callback(headers, 1, (php_http_pass_format_callback_t) php_http_buffer_appendf, str);
}
zend_string *php_http_header_value_array_to_string(zval *header)
{
zval *val;
php_http_buffer_t str;
php_http_buffer_init(&str);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(header), val)
{
zend_string *zs = php_http_header_value_to_string(val);
php_http_buffer_appendf(&str, str.used ? ", %s":"%s", zs->val);
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
php_http_buffer_fix(&str);
return php_http_cs2zs(str.data, str.used);
}
zend_string *php_http_header_value_to_string(zval *header)
{
switch (Z_TYPE_P(header)) {
case IS_TRUE:
return zend_string_init(ZEND_STRL("true"), 0);
case IS_FALSE:
return zend_string_init(ZEND_STRL("false"), 0);
case IS_ARRAY:
return php_http_header_value_array_to_string(header);
default:
return zval_get_string(header);
}
}
static zend_class_entry *php_http_header_class_entry;
zend_class_entry *php_http_header_get_class_entry(void)
{
return php_http_header_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader___construct, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, __construct)
{
char *name_str = NULL, *value_str = NULL;
size_t name_len = 0, value_len = 0;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!s!", &name_str, &name_len, &value_str, &value_len), invalid_arg, return);
if (name_str && name_len) {
char *pretty_str = estrndup(name_str, name_len);
zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("name"), php_http_pretty_key(pretty_str, name_len, 1, 1), name_len);
efree(pretty_str);
}
if (value_str && value_len) {
zend_update_property_stringl(php_http_header_class_entry, getThis(), ZEND_STRL("value"), value_str, value_len);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_serialize, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, serialize)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_buffer_t buf;
zend_string *zs;
zval name_tmp, value_tmp;
php_http_buffer_init(&buf);
zs = zval_get_string(zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0, &name_tmp));
php_http_buffer_appendz(&buf, zs);
zend_string_release(zs);
zs = zval_get_string(zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0, &value_tmp));
if (zs->len) {
php_http_buffer_appends(&buf, ": ");
php_http_buffer_appendz(&buf, zs);
} else {
php_http_buffer_appends(&buf, ":");
}
zend_string_release(zs);
RETURN_STR(php_http_cs2zs(buf.data, buf.used));
}
RETURN_EMPTY_STRING();
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, serialized)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, unserialize)
{
char *serialized_str;
size_t serialized_len;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized_str, &serialized_len)) {
HashTable ht;
zend_hash_init(&ht, 1, NULL, ZVAL_PTR_DTOR, 0);
if (SUCCESS == php_http_header_parse(serialized_str, serialized_len, &ht, NULL, NULL)) {
if (zend_hash_num_elements(&ht)) {
zend_string *zs, *key;
zend_ulong idx;
zend_hash_internal_pointer_reset(&ht);
switch (zend_hash_get_current_key(&ht, &key, &idx)) {
case HASH_KEY_IS_STRING:
zend_update_property_str(php_http_header_class_entry, getThis(), ZEND_STRL("name"), key);
break;
case HASH_KEY_IS_LONG:
zend_update_property_long(php_http_header_class_entry, getThis(), ZEND_STRL("name"), idx);
break;
default:
break;
}
zs = zval_get_string(zend_hash_get_current_data(&ht));
zend_update_property_str(php_http_header_class_entry, getThis(), ZEND_STRL("value"), zs);
zend_string_release(zs);
}
}
zend_hash_destroy(&ht);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_match, 0, 0, 1)
ZEND_ARG_INFO(0, value)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, match)
{
char *val_str = NULL;
size_t val_len = 0;
zend_long flags = PHP_HTTP_MATCH_LOOSE;
zend_string *zs;
zval value_tmp;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "|sl", &val_str, &val_len, &flags)) {
return;
}
zs = zval_get_string(zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0, &value_tmp));
RETVAL_BOOL(php_http_match(zs->val, val_str, flags));
zend_string_release(zs);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_negotiate, 0, 0, 1)
ZEND_ARG_INFO(0, supported)
ZEND_ARG_INFO(1, result)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, negotiate)
{
HashTable *supported, *rs;
zval name_tmp, value_tmp, *rs_array = NULL;
zend_string *zs;
char *sep_str = NULL;
size_t sep_len = 0;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "H|z", &supported, &rs_array)) {
return;
}
if (rs_array) {
ZVAL_DEREF(rs_array);
zval_dtor(rs_array);
array_init(rs_array);
}
zs = zval_get_string(zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("name"), 0, &name_tmp));
if (zend_string_equals_literal(zs, "Accept")) {
sep_str = "/";
sep_len = 1;
} else if (zend_string_equals_literal(zs, "Accept-Language")) {
sep_str = "-";
sep_len = 1;
}
zend_string_release(zs);
zs = zval_get_string(zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0, &value_tmp));
if ((rs = php_http_negotiate(zs->val, zs->len, supported, sep_str, sep_len))) {
PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(rs, supported, rs_array);
} else {
PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array);
}
zend_string_release(zs);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_getParams, 0, 0, 0)
ZEND_ARG_INFO(0, param_sep)
ZEND_ARG_INFO(0, arg_sep)
ZEND_ARG_INFO(0, val_sep)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, getParams)
{
zval value_tmp, zctor, zparams_obj, *zargs = NULL;
ZVAL_STRINGL(&zctor, "__construct", lenof("__construct"));
object_init_ex(&zparams_obj, php_http_params_get_class_entry());
zargs = (zval *) ecalloc(ZEND_NUM_ARGS()+1, sizeof(zval));
ZVAL_COPY_VALUE(&zargs[0], zend_read_property(php_http_header_class_entry, getThis(), ZEND_STRL("value"), 0, &value_tmp));
if (ZEND_NUM_ARGS()) {
zend_get_parameters_array(ZEND_NUM_ARGS(), ZEND_NUM_ARGS(), &zargs[1]);
}
if (SUCCESS == call_user_function(NULL, &zparams_obj, &zctor, return_value, ZEND_NUM_ARGS()+1, zargs)) {
RETVAL_ZVAL(&zparams_obj, 0, 1);
}
zval_ptr_dtor(&zctor);
if (zargs) {
efree(zargs);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpHeader_parse, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_ARG_INFO(0, header_class)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpHeader, parse)
{
char *header_str;
size_t header_len;
zend_class_entry *ce = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C", &header_str, &header_len, &ce)) {
array_init(return_value);
if (SUCCESS != php_http_header_parse(header_str, header_len, Z_ARRVAL_P(return_value), NULL, NULL)) {
zval_dtor(return_value);
RETURN_FALSE;
} else {
if (ce && instanceof_function(ce, php_http_header_class_entry)) {
php_http_arrkey_t key;
zval *val;
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(return_value), key.h, key.key, val)
{
zval zkey, zho;
if (key.key) {
ZVAL_STR_COPY(&zkey, key.key);
} else {
ZVAL_LONG(&zkey, key.h);
}
object_init_ex(&zho, ce);
Z_TRY_ADDREF_P(val);
zend_call_method_with_2_params(&zho, ce, NULL, "__construct", NULL, &zkey, val);
zval_ptr_dtor(val);
zval_ptr_dtor(&zkey);
if (key.key) {
add_assoc_zval_ex(return_value, key.key->val, key.key->len, &zho);
} else {
add_index_zval(return_value, key.h, &zho);
}
}
ZEND_HASH_FOREACH_END();
}
}
}
}
static zend_function_entry php_http_header_methods[] = {
PHP_ME(HttpHeader, __construct, ai_HttpHeader___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpHeader, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpHeader, __toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpHeader, toString, serialize, ai_HttpHeader_serialize, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeader, unserialize, ai_HttpHeader_unserialize, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeader, match, ai_HttpHeader_match, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeader, negotiate, ai_HttpHeader_negotiate, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeader, getParams, ai_HttpHeader_getParams, ZEND_ACC_PUBLIC)
PHP_ME(HttpHeader, parse, ai_HttpHeader_parse, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_header)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Header", php_http_header_methods);
php_http_header_class_entry = zend_register_internal_class(&ce);
zend_class_implements(php_http_header_class_entry, 1, zend_ce_serializable);
zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_LOOSE"), PHP_HTTP_MATCH_LOOSE);
zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_CASE"), PHP_HTTP_MATCH_CASE);
zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_WORD"), PHP_HTTP_MATCH_WORD);
zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_FULL"), PHP_HTTP_MATCH_FULL);
zend_declare_class_constant_long(php_http_header_class_entry, ZEND_STRL("MATCH_STRICT"), PHP_HTTP_MATCH_STRICT);
zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("name"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_header_class_entry, ZEND_STRL("value"), ZEND_ACC_PUBLIC);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_header.h 0000644 0001750 0000144 00000003031 12667772426 016457 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_HEADERS_H
#define PHP_HTTP_HEADERS_H
#include "php_http_info.h"
PHP_HTTP_API ZEND_RESULT_CODE php_http_header_parse(const char *header, size_t length, HashTable *headers, php_http_info_callback_t callback_func, void **callback_data);
PHP_HTTP_API void php_http_header_to_callback(HashTable *headers, zend_bool crlf, php_http_pass_format_callback_t cb, void *cb_arg);
PHP_HTTP_API void php_http_header_to_string(php_http_buffer_t *str, HashTable *headers);
PHP_HTTP_API zend_string *php_http_header_value_to_string(zval *header);
PHP_HTTP_API zend_string *php_http_header_value_array_to_string(zval *header);
PHP_HTTP_API zend_class_entry *php_http_header_get_class_entry(void);
PHP_MINIT_FUNCTION(http_header);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_info.c 0000644 0001750 0000144 00000010717 12667772426 016166 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
php_http_info_t *php_http_info_init(php_http_info_t *i)
{
if (!i) {
i = emalloc(sizeof(*i));
}
memset(i, 0, sizeof(*i));
return i;
}
void php_http_info_dtor(php_http_info_t *i)
{
switch (i->type) {
case PHP_HTTP_REQUEST:
PTR_SET(PHP_HTTP_INFO(i).request.method, NULL);
PTR_SET(PHP_HTTP_INFO(i).request.url, NULL);
break;
case PHP_HTTP_RESPONSE:
PTR_SET(PHP_HTTP_INFO(i).response.status, NULL);
break;
default:
break;
}
}
void php_http_info_free(php_http_info_t **i)
{
if (*i) {
php_http_info_dtor(*i);
efree(*i);
*i = NULL;
}
}
php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header)
{
const char *end, *http;
zend_bool free_info = !info;
/* sane parameter */
if ((!pre_header) || (!*pre_header)) {
return NULL;
}
/* where's the end of the line */
if (!(end = php_http_locate_eol(pre_header, NULL))) {
end = pre_header + strlen(pre_header);
}
/* there must be HTTP/1.x in the line */
if (!(http = php_http_locate_str(pre_header, end - pre_header, "HTTP/", lenof("HTTP/")))) {
return NULL;
}
info = php_http_info_init(info);
/* and nothing than SPACE or NUL after HTTP/X.x */
if (!php_http_version_parse(&info->http.version, http)
|| (http[lenof("HTTP/X.x")] && (!PHP_HTTP_IS_CTYPE(space, http[lenof("HTTP/X.x")])))) {
if (free_info) {
php_http_info_free(&info);
}
return NULL;
}
#if 0
{
char *line = estrndup(pre_header, end - pre_header);
fprintf(stderr, "http_parse_info('%s')\n", line);
efree(line);
}
#endif
/* is response */
if (pre_header == http) {
const char *status = NULL, *code = http + sizeof("HTTP/X.x");
info->type = PHP_HTTP_RESPONSE;
while (code < end && ' ' == *code) ++code;
if (code && end > code) {
/* rfc7230#3.1.2 The status-code element is a 3-digit integer code */
PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0');
PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0');
PHP_HTTP_INFO(info).response.code += *code++ - '0';
if (PHP_HTTP_INFO(info).response.code < 100 || PHP_HTTP_INFO(info).response.code > 599) {
if (free_info) {
php_http_info_free(&info);
}
return NULL;
}
status = code;
} else {
PHP_HTTP_INFO(info).response.code = 0;
}
if (status && end > status) {
while (' ' == *status) ++status;
PHP_HTTP_INFO(info).response.status = estrndup(status, end - status);
} else {
PHP_HTTP_INFO(info).response.status = NULL;
}
return info;
}
/* is request */
else if (*(http - 1) == ' ' && (!http[lenof("HTTP/X.x")] || http[lenof("HTTP/X.x")] == '\r' || http[lenof("HTTP/X.x")] == '\n')) {
const char *url = strchr(pre_header, ' ');
info->type = PHP_HTTP_REQUEST;
if (url && http > url) {
size_t url_len = url - pre_header;
PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len);
while (' ' == *url) ++url;
while (' ' == *(http-1)) --http;
if (http > url) {
/* CONNECT presents an authority only */
if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) {
PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, ~0);
} else {
PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, ~0);
}
if (!PHP_HTTP_INFO(info).request.url) {
PTR_SET(PHP_HTTP_INFO(info).request.method, NULL);
return NULL;
}
} else {
PTR_SET(PHP_HTTP_INFO(info).request.method, NULL);
return NULL;
}
} else {
PHP_HTTP_INFO(info).request.method = NULL;
PHP_HTTP_INFO(info).request.url = NULL;
}
return info;
}
/* some darn header containing HTTP/X.x */
else {
if (free_info) {
php_http_info_free(&info);
}
return NULL;
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_info.h 0000644 0001750 0000144 00000006120 12667772426 016164 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_INFO_H
#define PHP_HTTP_INFO_H
#include "php_http_version.h"
#include "php_http_url.h"
#define PHP_HTTP_INFO_REQUEST_FMT_ARGS(_http_ptr, tmp, eol) "%s %s HTTP/%u.%u" eol, \
(_http_ptr)->info.request.method?(_http_ptr)->info.request.method:"UNKNOWN", \
(_http_ptr)->info.request.method&&!strcasecmp((_http_ptr)->info.request.method,"CONNECT")?( \
(_http_ptr)->info.request.url?php_http_url_authority_to_string((_http_ptr)->info.request.url, &(tmp), NULL):"0"):( \
(_http_ptr)->info.request.url?php_http_url_to_string((_http_ptr)->info.request.url, &(tmp), NULL, 0):"/"), \
(_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \
(_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1
#define PHP_HTTP_INFO_RESPONSE_FMT_ARGS(_http_ptr, tmp, eol) "HTTP/%u.%u %d%s%s" eol, \
(_http_ptr)->version.major||(_http_ptr)->version.major?(_http_ptr)->version.major:1, \
(_http_ptr)->version.major||(_http_ptr)->version.minor?(_http_ptr)->version.minor:1, \
(_http_ptr)->info.response.code?(_http_ptr)->info.response.code:200, \
(_http_ptr)->info.response.status&&*(_http_ptr)->info.response.status ? " ":"", \
STR_PTR((_http_ptr)->info.response.status)
typedef struct php_http_info_data {
union {
/* GET /foo/bar */
struct { char *method; php_http_url_t *url; } request;
/* 200 Ok */
struct { unsigned code; char *status; } response;
} info;
php_http_version_t version;
} php_http_info_data_t;
#undef PHP_HTTP_REQUEST
#undef PHP_HTTP_RESPONSE
typedef enum php_http_info_type {
PHP_HTTP_NONE = 0,
PHP_HTTP_REQUEST,
PHP_HTTP_RESPONSE
} php_http_info_type_t;
#define PHP_HTTP_INFO(ptr) (ptr)->http.info
#define PHP_HTTP_INFO_IMPL(_http, _type) \
php_http_info_data_t _http; \
php_http_info_type_t _type;
typedef struct php_http_info {
PHP_HTTP_INFO_IMPL(http, type)
} php_http_info_t;
typedef zend_bool (*php_http_info_callback_t)(void **callback_data, HashTable **headers, php_http_info_t *info);
PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *info);
PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header);
PHP_HTTP_API void php_http_info_dtor(php_http_info_t *info);
PHP_HTTP_API void php_http_info_free(php_http_info_t **info);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message_body.c 0000644 0001750 0000144 00000062730 12667772426 017676 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
#define BOUNDARY_OPEN(body) \
do {\
size_t size = php_http_message_body_size(body); \
if (size) { \
php_stream_truncate_set_size(php_http_message_body_stream(body), size - lenof("--" PHP_HTTP_CRLF)); \
php_http_message_body_append(body, ZEND_STRL(PHP_HTTP_CRLF)); \
} else { \
php_http_message_body_appendf(body, "--%s" PHP_HTTP_CRLF, php_http_message_body_boundary(body)); \
} \
} while(0)
#define BOUNDARY_CLOSE(body) \
php_http_message_body_appendf(body, PHP_HTTP_CRLF "--%s--" PHP_HTTP_CRLF, php_http_message_body_boundary(body))
static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, const char *name, HashTable *fields);
static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const char *name, HashTable *files);
php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body_ptr, php_stream *stream)
{
php_http_message_body_t *body;
if (body_ptr && *body_ptr) {
body = *body_ptr;
php_http_message_body_addref(body);
return body;
}
body = ecalloc(1, sizeof(php_http_message_body_t));
body->refcount = 1;
if (stream) {
body->res = stream->res;
++GC_REFCOUNT(body->res);
} else {
stream = php_stream_temp_create(TEMP_STREAM_DEFAULT, 0xffff);
body->res = stream->res;
}
php_stream_auto_cleanup(stream);
if (body_ptr) {
*body_ptr = body;
}
return body;
}
unsigned php_http_message_body_addref(php_http_message_body_t *body)
{
return ++body->refcount;
}
php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to)
{
if (from) {
if (to) {
php_stream_truncate_set_size(php_http_message_body_stream(to), 0);
} else {
to = php_http_message_body_init(NULL, NULL);
}
php_http_message_body_to_stream(from, php_http_message_body_stream(to), 0, 0);
if (to->boundary) {
efree(to->boundary);
}
if (from->boundary) {
to->boundary = estrdup(from->boundary);
}
} else {
to = NULL;
}
return to;
}
void php_http_message_body_free(php_http_message_body_t **body_ptr)
{
if (*body_ptr) {
php_http_message_body_t *body = *body_ptr;
if (!--body->refcount) {
zend_list_delete(body->res);
PTR_FREE(body->boundary);
efree(body);
}
*body_ptr = NULL;
}
}
const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body)
{
php_stream_stat(php_http_message_body_stream(body), &body->ssb);
return &body->ssb;
}
const char *php_http_message_body_boundary(php_http_message_body_t *body)
{
if (!body->boundary) {
union { double dbl; int num[2]; } data;
data.dbl = php_combined_lcg();
spprintf(&body->boundary, 0, "%x.%x", data.num[0], data.num[1]);
}
return body->boundary;
}
char *php_http_message_body_etag(php_http_message_body_t *body)
{
php_http_etag_t *etag;
php_stream *s = php_http_message_body_stream(body);
/* real file or temp buffer ? */
if (s->ops != &php_stream_temp_ops && s->ops != &php_stream_memory_ops) {
php_stream_stat(php_http_message_body_stream(body), &body->ssb);
if (body->ssb.sb.st_mtime) {
char *etag;
spprintf(&etag, 0, "%lx-%lx-%lx", body->ssb.sb.st_ino, body->ssb.sb.st_mtime, body->ssb.sb.st_size);
return etag;
}
}
/* content based */
if ((etag = php_http_etag_init(PHP_HTTP_G->env.etag_mode))) {
php_http_message_body_to_callback(body, (php_http_pass_callback_t) php_http_etag_update, etag, 0, 0);
return php_http_etag_finish(etag);
}
return NULL;
}
zend_string *php_http_message_body_to_string(php_http_message_body_t *body, off_t offset, size_t forlen)
{
php_stream *s = php_http_message_body_stream(body);
php_stream_seek(s, offset, SEEK_SET);
if (!forlen) {
forlen = -1;
}
return php_stream_copy_to_mem(s, forlen, 0);
}
ZEND_RESULT_CODE php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *dst, off_t offset, size_t forlen)
{
php_stream *s = php_http_message_body_stream(body);
php_stream_seek(s, offset, SEEK_SET);
if (!forlen) {
forlen = -1;
}
return php_stream_copy_to_stream_ex(s, dst, forlen, NULL);
}
ZEND_RESULT_CODE php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen)
{
php_stream *s = php_http_message_body_stream(body);
char *buf = emalloc(0x1000);
php_stream_seek(s, offset, SEEK_SET);
if (!forlen) {
forlen = -1;
}
while (!php_stream_eof(s)) {
size_t read = php_stream_read(s, buf, MIN(forlen, 0x1000));
if (read) {
if (-1 == cb(cb_arg, buf, read)) {
return FAILURE;
}
}
if (read < MIN(forlen, sizeof(buf))) {
break;
}
if (forlen && !(forlen -= read)) {
break;
}
}
efree(buf);
return SUCCESS;
}
size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len)
{
php_stream *s;
size_t written;
if (!(s = php_http_message_body_stream(body))) {
return -1;
}
if (s->ops->seek) {
php_stream_seek(s, 0, SEEK_END);
}
written = php_stream_write(s, buf, len);
if (written != len) {
php_error_docref(NULL, E_WARNING, "Failed to append %zu bytes to body; wrote %zu", len, written);
}
return len;
}
size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...)
{
va_list argv;
char *print_str;
size_t print_len;
va_start(argv, fmt);
print_len = vspprintf(&print_str, 0, fmt, argv);
va_end(argv);
print_len = php_http_message_body_append(body, print_str, print_len);
efree(print_str);
return print_len;
}
ZEND_RESULT_CODE php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files)
{
if (fields) {
if (SUCCESS != add_recursive_fields(body, NULL, fields)) {
return FAILURE;
}
}
if (files) {
if (SUCCESS != add_recursive_files(body, NULL, files)) {
return FAILURE;
}
}
return SUCCESS;
}
void php_http_message_body_add_part(php_http_message_body_t *body, php_http_message_t *part)
{
BOUNDARY_OPEN(body);
php_http_message_to_callback(part, (php_http_pass_callback_t) php_http_message_body_append, body);
BOUNDARY_CLOSE(body);
}
ZEND_RESULT_CODE php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len)
{
zend_string *safe_name = zend_string_init(name, strlen(name), 0);
safe_name = php_addslashes(safe_name, 1);
BOUNDARY_OPEN(body);
php_http_message_body_appendf(
body,
"Content-Disposition: form-data; name=\"%s\"" PHP_HTTP_CRLF
"" PHP_HTTP_CRLF,
safe_name->val
);
php_http_message_body_append(body, value_str, value_len);
BOUNDARY_CLOSE(body);
zend_string_release(safe_name);
return SUCCESS;
}
ZEND_RESULT_CODE php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *path, php_stream *in)
{
size_t path_len = strlen(path);
char *path_dup = estrndup(path, path_len);
zend_string *base_name, *safe_name = zend_string_init(name, strlen(name), 0);
safe_name = php_addslashes(safe_name, 1);
base_name = php_basename(path_dup, path_len, NULL, 0);
BOUNDARY_OPEN(body);
php_http_message_body_appendf(
body,
"Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"" PHP_HTTP_CRLF
"Content-Transfer-Encoding: binary" PHP_HTTP_CRLF
"Content-Type: %s" PHP_HTTP_CRLF
PHP_HTTP_CRLF,
safe_name->val, base_name->val, ctype
);
php_stream_copy_to_stream_ex(in, php_http_message_body_stream(body), PHP_STREAM_COPY_ALL, NULL);
BOUNDARY_CLOSE(body);
zend_string_release(safe_name);
zend_string_release(base_name);
efree(path_dup);
return SUCCESS;
}
static inline char *format_key(php_http_arrkey_t *key, const char *prefix) {
char *new_key = NULL;
if (prefix && *prefix) {
if (key->key) {
spprintf(&new_key, 0, "%s[%s]", prefix, key->key->val);
} else {
spprintf(&new_key, 0, "%s[%lu]", prefix, key->h);
}
} else if (key->key) {
new_key = estrdup(key->key->val);
} else {
new_key = estrdup("");
}
return new_key;
}
static ZEND_RESULT_CODE add_recursive_field_value(php_http_message_body_t *body, const char *name, zval *value)
{
zend_string *zs = zval_get_string(value);
ZEND_RESULT_CODE rc = php_http_message_body_add_form_field(body, name, zs->val, zs->len);
zend_string_release(zs);
return rc;
}
static ZEND_RESULT_CODE add_recursive_fields(php_http_message_body_t *body, const char *name, HashTable *fields)
{
zval *val;
php_http_arrkey_t key;
if (!ZEND_HASH_GET_APPLY_COUNT(fields)) {
ZEND_HASH_INC_APPLY_COUNT(fields);
ZEND_HASH_FOREACH_KEY_VAL_IND(fields, key.h, key.key, val)
{
char *str = format_key(&key, name);
if (Z_TYPE_P(val) != IS_ARRAY && Z_TYPE_P(val) != IS_OBJECT) {
if (SUCCESS != add_recursive_field_value(body, str, val)) {
efree(str);
ZEND_HASH_DEC_APPLY_COUNT(fields);
return FAILURE;
}
} else if (SUCCESS != add_recursive_fields(body, str, HASH_OF(val))) {
efree(str);
ZEND_HASH_DEC_APPLY_COUNT(fields);
return FAILURE;
}
efree(str);
}
ZEND_HASH_FOREACH_END();
ZEND_HASH_DEC_APPLY_COUNT(fields);
}
return SUCCESS;
}
static ZEND_RESULT_CODE add_recursive_files(php_http_message_body_t *body, const char *name, HashTable *files)
{
zval *zdata = NULL, *zfile, *zname, *ztype;
/* single entry */
if (!(zname = zend_hash_str_find(files, ZEND_STRL("name")))
|| !(ztype = zend_hash_str_find(files, ZEND_STRL("type")))
|| !(zfile = zend_hash_str_find(files, ZEND_STRL("file")))
) {
zval *val;
php_http_arrkey_t key;
if (!ZEND_HASH_GET_APPLY_COUNT(files)) {
ZEND_HASH_INC_APPLY_COUNT(files);
ZEND_HASH_FOREACH_KEY_VAL_IND(files, key.h, key.key, val)
{
if (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT) {
char *str = format_key(&key, name);
if (SUCCESS != add_recursive_files(body, str, HASH_OF(val))) {
efree(str);
ZEND_HASH_DEC_APPLY_COUNT(files);
return FAILURE;
}
efree(str);
}
}
ZEND_HASH_FOREACH_END();
ZEND_HASH_DEC_APPLY_COUNT(files);
}
return SUCCESS;
} else {
/* stream entry */
php_stream *stream;
zend_string *zfc = zval_get_string(zfile);
if ((zdata = zend_hash_str_find(files, ZEND_STRL("data")))) {
if (Z_TYPE_P(zdata) == IS_RESOURCE) {
php_stream_from_zval_no_verify(stream, zdata);
} else {
zend_string *tmp = zval_get_string(zdata);
stream = php_stream_memory_open(TEMP_STREAM_READONLY, tmp->val, tmp->len);
zend_string_release(tmp);
}
} else {
stream = php_stream_open_wrapper(zfc->val, "r", REPORT_ERRORS|USE_PATH, NULL);
}
if (!stream) {
zend_string_release(zfc);
return FAILURE;
} else {
zend_string *znc = zval_get_string(zname), *ztc = zval_get_string(ztype);
php_http_arrkey_t arrkey = {0, znc};
char *key = format_key(&arrkey, name);
ZEND_RESULT_CODE ret = php_http_message_body_add_form_file(body, key, ztc->val, zfc->val, stream);
efree(key);
zend_string_release(znc);
zend_string_release(ztc);
zend_string_release(zfc);
if (!zdata || Z_TYPE_P(zdata) != IS_RESOURCE) {
php_stream_close(stream);
}
return ret;
}
}
}
struct splitbody_arg {
php_http_buffer_t buf;
php_http_message_parser_t *parser;
char *boundary_str;
size_t boundary_len;
size_t consumed;
};
static size_t splitbody(void *opaque, char *buf, size_t len)
{
struct splitbody_arg *arg = opaque;
const char *boundary = NULL;
size_t consumed = 0;
int first_boundary;
do {
first_boundary = !(consumed || arg->consumed);
if ((boundary = php_http_locate_str(buf, len, arg->boundary_str + first_boundary, arg->boundary_len - first_boundary))) {
size_t real_boundary_len = arg->boundary_len - 1, cut;
const char *real_boundary = boundary + !first_boundary;
int eol_len = 0;
if (buf + len <= real_boundary + real_boundary_len) {
/* if we just have enough data for the boundary, it's just a byte too less */
arg->consumed += consumed;
return consumed;
}
if (!first_boundary) {
/* this is not the first boundary, read rest of this message */
php_http_buffer_append(&arg->buf, buf, real_boundary - buf);
php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message);
}
/* move after the boundary */
cut = real_boundary - buf + real_boundary_len;
buf += cut;
len -= cut;
consumed += cut;
if (buf == php_http_locate_bin_eol(buf, len, &eol_len)) {
/* skip CRLF */
buf += eol_len;
len -= eol_len;
consumed += eol_len;
if (!first_boundary) {
/* advance messages */
php_http_message_t *msg;
msg = php_http_message_init(NULL, 0, NULL);
msg->parent = arg->parser->message;
arg->parser->message = msg;
}
} else {
/* is this the last boundary? */
if (*buf == '-') {
/* ignore the rest */
consumed += len;
len = 0;
} else {
/* let this be garbage */
php_error_docref(NULL, E_WARNING, "Malformed multipart boundary at pos %zu", consumed);
return -1;
}
}
}
} while (boundary && len);
/* let there be room for the next boundary */
if (len > arg->boundary_len) {
consumed += len - arg->boundary_len;
php_http_buffer_append(&arg->buf, buf, len - arg->boundary_len);
php_http_message_parser_parse(arg->parser, &arg->buf, 0, &arg->parser->message);
}
arg->consumed += consumed;
return consumed;
}
php_http_message_t *php_http_message_body_split(php_http_message_body_t *body, const char *boundary)
{
php_stream *s = php_http_message_body_stream(body);
php_http_buffer_t *tmp = NULL;
php_http_message_t *msg = NULL;
struct splitbody_arg arg;
php_http_buffer_init(&arg.buf);
arg.parser = php_http_message_parser_init(NULL);
arg.boundary_len = spprintf(&arg.boundary_str, 0, "\n--%s", boundary);
arg.consumed = 0;
php_stream_rewind(s);
while (!php_stream_eof(s)) {
php_http_buffer_passthru(&tmp, 0x1000, (php_http_buffer_pass_func_t) _php_stream_read, s, splitbody, &arg);
}
msg = arg.parser->message;
arg.parser->message = NULL;
php_http_buffer_free(&tmp);
php_http_message_parser_free(&arg.parser);
php_http_buffer_dtor(&arg.buf);
PTR_FREE(arg.boundary_str);
return msg;
}
static zend_class_entry *php_http_message_body_class_entry;
zend_class_entry *php_http_get_message_body_class_entry(void)
{
return php_http_message_body_class_entry;
}
static zend_object_handlers php_http_message_body_object_handlers;
zend_object *php_http_message_body_object_new(zend_class_entry *ce)
{
return &php_http_message_body_object_new_ex(ce, NULL)->zo;
}
php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body)
{
php_http_message_body_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, php_http_message_body_class_entry);
object_properties_init(&o->zo, ce);
if (body) {
o->body = body;
}
o->zo.handlers = &php_http_message_body_object_handlers;
return o;
}
zend_object *php_http_message_body_object_clone(zval *object)
{
php_http_message_body_object_t *new_obj = NULL;
php_http_message_body_object_t *old_obj = PHP_HTTP_OBJ(NULL, object);
php_http_message_body_t *body = php_http_message_body_copy(old_obj->body, NULL);
new_obj = php_http_message_body_object_new_ex(old_obj->zo.ce, body);
zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
return &new_obj->zo;
}
void php_http_message_body_object_free(zend_object *object)
{
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(object, NULL);
php_http_message_body_free(&obj->body);
zend_object_std_dtor(object);
}
#define PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj) \
do { \
if (!obj->body) { \
obj->body = php_http_message_body_init(NULL, NULL); \
} \
} while(0)
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___construct, 0, 0, 0)
ZEND_ARG_INFO(0, stream)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, __construct)
{
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
zval *zstream = NULL;
php_stream *stream;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|r!", &zstream), invalid_arg, return);
if (zstream) {
php_http_expect(php_stream_from_zval_no_verify(stream, zstream), unexpected_val, return);
if (obj->body) {
php_http_message_body_free(&obj->body);
}
obj->body = php_http_message_body_init(NULL, stream);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody___toString, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, __toString)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
zend_string *zs;
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
zs = php_http_message_body_to_string(obj->body, 0, 0);
if (zs) {
RETURN_STR(zs);
}
}
RETURN_EMPTY_STRING();
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, serialized)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, unserialize)
{
char *us_str;
size_t us_len;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &us_str, &us_len)) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
php_stream *s = php_stream_memory_open(0, us_str, us_len);
obj->body = php_http_message_body_init(NULL, s);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toStream, 0, 0, 1)
ZEND_ARG_INFO(0, stream)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, maxlen)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, toStream)
{
zval *zstream;
zend_long offset = 0, forlen = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r|ll", &zstream, &offset, &forlen)) {
php_stream *stream;
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
php_stream_from_zval(stream, zstream);
php_http_message_body_to_stream(obj->body, stream, offset, forlen);
RETURN_ZVAL(getThis(), 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_toCallback, 0, 0, 1)
ZEND_ARG_INFO(0, callback)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, maxlen)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, toCallback)
{
php_http_pass_fcall_arg_t fcd;
zend_long offset = 0, forlen = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f|ll", &fcd.fci, &fcd.fcc, &offset, &forlen)) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
ZVAL_COPY(&fcd.fcz, getThis());
php_http_message_body_to_callback(obj->body, php_http_pass_fcall_callback, &fcd, offset, forlen);
zend_fcall_info_args_clear(&fcd.fci, 1);
zval_ptr_dtor(&fcd.fcz);
RETURN_ZVAL(getThis(), 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getResource, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, getResource)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
++GC_REFCOUNT(obj->body->res);
RETVAL_RES(obj->body->res);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_getBoundary, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, getBoundary)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_body_object_t * obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
if (obj->body->boundary) {
RETURN_STRING(obj->body->boundary);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_append, 0, 0, 1)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, append)
{
char *str;
size_t len;
php_http_message_body_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
php_http_expect(len == php_http_message_body_append(obj->body, str, len), runtime, return);
RETURN_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addForm, 0, 0, 0)
ZEND_ARG_ARRAY_INFO(0, fields, 1)
ZEND_ARG_ARRAY_INFO(0, files, 1)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, addForm)
{
HashTable *fields = NULL, *files = NULL;
php_http_message_body_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|h!h!", &fields, &files), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
php_http_expect(SUCCESS == php_http_message_body_add_form(obj->body, fields, files), runtime, return);
RETURN_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_addPart, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, addPart)
{
zval *zobj;
php_http_message_body_object_t *obj;
php_http_message_object_t *mobj;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zobj, php_http_message_get_class_entry()), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
mobj = PHP_HTTP_OBJ(NULL, zobj);
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh);
php_http_message_body_add_part(obj->body, mobj->message);
zend_restore_error_handling(&zeh);
if (!EG(exception)) {
RETURN_ZVAL(getThis(), 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_etag, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, etag)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *etag;
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
if ((etag = php_http_message_body_etag(obj->body))) {
RETURN_STR(php_http_cs2zs(etag, strlen(etag)));
} else {
RETURN_FALSE;
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageBody_stat, 0, 0, 0)
ZEND_ARG_INFO(0, field)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpMessageBody, stat)
{
char *field_str = NULL;
size_t field_len = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|s", &field_str, &field_len)) {
php_http_message_body_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
const php_stream_statbuf *sb;
PHP_HTTP_MESSAGE_BODY_OBJECT_INIT(obj);
if ((sb = php_http_message_body_stat(obj->body))) {
if (field_str && field_len) {
switch (*field_str) {
case 's':
case 'S':
RETURN_LONG(sb->sb.st_size);
break;
case 'a':
case 'A':
RETURN_LONG(sb->sb.st_atime);
break;
case 'm':
case 'M':
RETURN_LONG(sb->sb.st_mtime);
break;
case 'c':
case 'C':
RETURN_LONG(sb->sb.st_ctime);
break;
default:
php_error_docref(NULL, E_WARNING, "Unknown stat field: '%s' (should be one of [s]ize, [a]time, [m]time or [c]time)", field_str);
break;
}
} else {
object_init(return_value);
add_property_long_ex(return_value, ZEND_STRL("size"), sb->sb.st_size);
add_property_long_ex(return_value, ZEND_STRL("atime"), sb->sb.st_atime);
add_property_long_ex(return_value, ZEND_STRL("mtime"), sb->sb.st_mtime);
add_property_long_ex(return_value, ZEND_STRL("ctime"), sb->sb.st_ctime);
}
}
}
}
static zend_function_entry php_http_message_body_methods[] = {
PHP_ME(HttpMessageBody, __construct, ai_HttpMessageBody___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpMessageBody, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
PHP_MALIAS(HttpMessageBody, toString, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
PHP_MALIAS(HttpMessageBody, serialize, __toString, ai_HttpMessageBody___toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, unserialize, ai_HttpMessageBody_unserialize, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, toStream, ai_HttpMessageBody_toStream, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, toCallback, ai_HttpMessageBody_toCallback, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, getResource, ai_HttpMessageBody_getResource, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, getBoundary, ai_HttpMessageBody_getBoundary, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, append, ai_HttpMessageBody_append, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, addForm, ai_HttpMessageBody_addForm, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, addPart, ai_HttpMessageBody_addPart, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, etag, ai_HttpMessageBody_etag, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageBody, stat, ai_HttpMessageBody_stat, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_message_body)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http\\Message", "Body", php_http_message_body_methods);
php_http_message_body_class_entry = zend_register_internal_class(&ce);
php_http_message_body_class_entry->create_object = php_http_message_body_object_new;
memcpy(&php_http_message_body_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_message_body_object_handlers.offset = XtOffsetOf(php_http_message_body_object_t, zo);
php_http_message_body_object_handlers.clone_obj = php_http_message_body_object_clone;
php_http_message_body_object_handlers.free_obj = php_http_message_body_object_free;
zend_class_implements(php_http_message_body_class_entry, 1, zend_ce_serializable);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message_body.h 0000644 0001750 0000144 00000007655 12667772426 017710 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_MESSAGE_BODY_H
#define PHP_HTTP_MESSAGE_BODY_H
typedef struct php_http_message_body {
php_stream_statbuf ssb;
zend_resource *res;
char *boundary;
unsigned refcount;
} php_http_message_body_t;
struct php_http_message;
PHP_HTTP_API php_http_message_body_t *php_http_message_body_init(php_http_message_body_t **body, php_stream *stream);
PHP_HTTP_API unsigned php_http_message_body_addref(php_http_message_body_t *body);
PHP_HTTP_API php_http_message_body_t *php_http_message_body_copy(php_http_message_body_t *from, php_http_message_body_t *to);
PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form(php_http_message_body_t *body, HashTable *fields, HashTable *files);
PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form_field(php_http_message_body_t *body, const char *name, const char *value_str, size_t value_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_add_form_file(php_http_message_body_t *body, const char *name, const char *ctype, const char *file, php_stream *stream);
PHP_HTTP_API void php_http_message_body_add_part(php_http_message_body_t *body, struct php_http_message *part);
PHP_HTTP_API size_t php_http_message_body_append(php_http_message_body_t *body, const char *buf, size_t len);
PHP_HTTP_API size_t php_http_message_body_appendf(php_http_message_body_t *body, const char *fmt, ...);
PHP_HTTP_API zend_string *php_http_message_body_to_string(php_http_message_body_t *body, off_t offset, size_t forlen);
PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_to_stream(php_http_message_body_t *body, php_stream *s, off_t offset, size_t forlen);
PHP_HTTP_API ZEND_RESULT_CODE php_http_message_body_to_callback(php_http_message_body_t *body, php_http_pass_callback_t cb, void *cb_arg, off_t offset, size_t forlen);
PHP_HTTP_API void php_http_message_body_free(php_http_message_body_t **body);
PHP_HTTP_API const php_stream_statbuf *php_http_message_body_stat(php_http_message_body_t *body);
PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body);
PHP_HTTP_API const char *php_http_message_body_boundary(php_http_message_body_t *body);
PHP_HTTP_API struct php_http_message *php_http_message_body_split(php_http_message_body_t *body, const char *boundary);
static inline size_t php_http_message_body_size(php_http_message_body_t *b)
{
return php_http_message_body_stat(b)->sb.st_size;
}
static inline time_t php_http_message_body_mtime(php_http_message_body_t *b)
{
return php_http_message_body_stat(b)->sb.st_mtime;
}
static inline php_stream *php_http_message_body_stream(php_http_message_body_t *body)
{
return body->res->ptr;
}
typedef struct php_http_message_body_object {
php_http_message_body_t *body;
zend_object zo;
} php_http_message_body_object_t;
PHP_HTTP_API zend_class_entry *php_http_get_message_body_class_entry(void);
PHP_MINIT_FUNCTION(http_message_body);
zend_object *php_http_message_body_object_new(zend_class_entry *ce);
php_http_message_body_object_t *php_http_message_body_object_new_ex(zend_class_entry *ce, php_http_message_body_t *body);
zend_object *php_http_message_body_object_clone(zval *object);
void php_http_message_body_object_free(zend_object *object);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message.c 0000644 0001750 0000144 00000177777 12667772426 016703 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static void message_headers(php_http_message_t *msg, php_http_buffer_t *str);
zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info)
{
php_http_message_t *old = *message;
/* advance message */
if (!old || old->type || zend_hash_num_elements(&old->hdrs)) {
(*message) = php_http_message_init(NULL, 0, NULL);
(*message)->parent = old;
if (headers) {
(*headers) = &((*message)->hdrs);
}
}
if (info) {
php_http_message_set_info(*message, info);
}
return old != *message;
}
php_http_message_t *php_http_message_init(php_http_message_t *message, php_http_message_type_t type, php_http_message_body_t *body)
{
if (!message) {
message = emalloc(sizeof(*message));
}
memset(message, 0, sizeof(*message));
php_http_message_set_type(message, type);
message->http.version.major = 1;
message->http.version.minor = 1;
zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
message->body = body ? body : php_http_message_body_init(NULL, NULL);
return message;
}
php_http_message_t *php_http_message_init_env(php_http_message_t *message, php_http_message_type_t type)
{
int free_msg = !message;
zval *sval, tval;
php_http_message_body_t *mbody;
switch (type) {
case PHP_HTTP_REQUEST:
mbody = php_http_env_get_request_body();
php_http_message_body_addref(mbody);
message = php_http_message_init(message, type, mbody);
if ((sval = php_http_env_get_server_var(ZEND_STRL("SERVER_PROTOCOL"), 1)) && !strncmp(Z_STRVAL_P(sval), "HTTP/", lenof("HTTP/"))) {
php_http_version_parse(&message->http.version, Z_STRVAL_P(sval));
}
if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_METHOD"), 1))) {
message->http.info.request.method = estrdup(Z_STRVAL_P(sval));
}
if ((sval = php_http_env_get_server_var(ZEND_STRL("REQUEST_URI"), 1))) {
message->http.info.request.url = php_http_url_parse(Z_STRVAL_P(sval), Z_STRLEN_P(sval), ~0);
}
php_http_env_get_request_headers(&message->hdrs);
break;
case PHP_HTTP_RESPONSE:
message = php_http_message_init(NULL, type, NULL);
if (!SG(sapi_headers).http_status_line || !php_http_info_parse((php_http_info_t *) &message->http, SG(sapi_headers).http_status_line)) {
if (!(message->http.info.response.code = SG(sapi_headers).http_response_code)) {
message->http.info.response.code = 200;
}
message->http.info.response.status = estrdup(php_http_env_get_response_status_for_code(message->http.info.response.code));
}
php_http_env_get_response_headers(&message->hdrs);
if (php_output_get_level()) {
if (php_output_get_status() & PHP_OUTPUT_SENT) {
php_error_docref(NULL, E_WARNING, "Could not fetch response body, output has already been sent at %s:%d", php_output_get_start_filename(), php_output_get_start_lineno());
goto error;
} else if (SUCCESS != php_output_get_contents(&tval)) {
php_error_docref(NULL, E_WARNING, "Could not fetch response body");
goto error;
} else {
php_http_message_body_append(message->body, Z_STRVAL(tval), Z_STRLEN(tval));
zval_dtor(&tval);
}
}
break;
default:
error:
if (free_msg) {
if (message) {
php_http_message_free(&message);
}
} else {
message = NULL;
}
break;
}
return message;
}
php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy)
{
php_http_message_parser_t p;
php_http_buffer_t buf;
unsigned flags = PHP_HTTP_MESSAGE_PARSER_CLEANUP;
int free_msg;
php_http_buffer_from_string_ex(&buf, str, len);
php_http_message_parser_init(&p);
if ((free_msg = !msg)) {
msg = php_http_message_init(NULL, 0, NULL);
}
if (greedy) {
flags |= PHP_HTTP_MESSAGE_PARSER_GREEDY;
}
if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse(&p, &buf, flags, &msg)) {
if (free_msg) {
php_http_message_free(&msg);
}
msg = NULL;
}
php_http_message_parser_dtor(&p);
php_http_buffer_dtor(&buf);
return msg;
}
zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len)
{
zval *ret;
char *key;
ALLOCA_FLAG(free_key);
key = do_alloca(key_len + 1, free_key);
memcpy(key, key_str, key_len);
key[key_len] = '\0';
php_http_pretty_key(key, key_len, 1, 1);
ret = zend_symtable_str_find(&msg->hdrs, key, key_len);
free_alloca(key, free_key);
return ret;
}
zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary)
{
zend_string *ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type"));
zend_bool is_multipart = 0;
if (ct) {
php_http_params_opts_t popts;
HashTable params;
ZEND_INIT_SYMTABLE(¶ms);
php_http_params_opts_default_get(&popts);
popts.input.str = ct->val;
popts.input.len = ct->len;
if (php_http_params_parse(¶ms, &popts)) {
zval *cur, *arg;
zend_string *ct_str;
zend_ulong index;
zend_hash_internal_pointer_reset(¶ms);
if ((cur = zend_hash_get_current_data(¶ms))
&& (Z_TYPE_P(cur) == IS_ARRAY)
&& (HASH_KEY_IS_STRING == zend_hash_get_current_key(¶ms, &ct_str, &index))
) {
if (php_http_match(ct_str->val, "multipart", PHP_HTTP_MATCH_WORD)) {
is_multipart = 1;
/* get boundary */
if (boundary
&& (arg = zend_hash_str_find(Z_ARRVAL_P(cur), ZEND_STRL("arguments")))
&& Z_TYPE_P(arg) == IS_ARRAY
) {
zval *val;
php_http_arrkey_t key;
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(arg), key.h, key.key, val)
{
if (key.key && key.key->len == lenof("boundary") && !strcasecmp(key.key->val, "boundary")) {
zend_string *bnd = zval_get_string(val);
if (bnd->len) {
*boundary = estrndup(bnd->val, bnd->len);
}
zend_string_release(bnd);
}
}
ZEND_HASH_FOREACH_END();
}
}
}
}
zend_hash_destroy(¶ms);
zend_string_release(ct);
}
return is_multipart;
}
/* */
void php_http_message_set_type(php_http_message_t *message, php_http_message_type_t type)
{
/* just act if different */
if (type != message->type) {
/* free request info */
switch (message->type) {
case PHP_HTTP_REQUEST:
PTR_FREE(message->http.info.request.method);
PTR_FREE(message->http.info.request.url);
break;
case PHP_HTTP_RESPONSE:
PTR_FREE(message->http.info.response.status);
break;
default:
break;
}
message->type = type;
memset(&message->http, 0, sizeof(message->http));
}
}
void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info)
{
php_http_message_set_type(message, info->type);
message->http.version = info->http.version;
switch (message->type) {
case PHP_HTTP_REQUEST:
PTR_SET(PHP_HTTP_INFO(message).request.url, PHP_HTTP_INFO(info).request.url ? php_http_url_copy(PHP_HTTP_INFO(info).request.url, 0) : NULL);
PTR_SET(PHP_HTTP_INFO(message).request.method, PHP_HTTP_INFO(info).request.method ? estrdup(PHP_HTTP_INFO(info).request.method) : NULL);
break;
case PHP_HTTP_RESPONSE:
PHP_HTTP_INFO(message).response.code = PHP_HTTP_INFO(info).response.code;
PTR_SET(PHP_HTTP_INFO(message).response.status, PHP_HTTP_INFO(info).response.status ? estrdup(PHP_HTTP_INFO(info).response.status) : NULL);
break;
default:
break;
}
}
void php_http_message_update_headers(php_http_message_t *msg)
{
zval h;
size_t size;
zend_string *cl;
if (php_http_message_body_stream(msg->body)->readfilters.head) {
/* if a read stream filter is attached to the body the caller must also care for the headers */
} else if (php_http_message_header(msg, ZEND_STRL("Content-Range"))) {
/* don't mess around with a Content-Range message */
} else if ((size = php_http_message_body_size(msg->body))) {
ZVAL_LONG(&h, size);
zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h);
if (msg->body->boundary) {
char *str;
size_t len;
zend_string *ct;
if (!(ct = php_http_message_header_string(msg, ZEND_STRL("Content-Type")))) {
len = spprintf(&str, 0, "multipart/form-data; boundary=\"%s\"", msg->body->boundary);
ZVAL_STR(&h, php_http_cs2zs(str, len));
zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h);
} else if (!php_http_match(ct->val, "boundary=", PHP_HTTP_MATCH_WORD)) {
len = spprintf(&str, 0, "%s; boundary=\"%s\"", ct->val, msg->body->boundary);
ZVAL_STR(&h, php_http_cs2zs(str, len));
zend_hash_str_update(&msg->hdrs, "Content-Type", lenof("Content-Type"), &h);
zend_string_release(ct);
} else {
zend_string_release(ct);
}
}
} else if ((cl = php_http_message_header_string(msg, ZEND_STRL("Content-Length")))) {
if (!zend_string_equals_literal(cl, "0")) {
/* body->size == 0, so get rid of old Content-Length */
zend_hash_str_del(&msg->hdrs, ZEND_STRL("Content-Length"));
}
zend_string_release(cl);
} else if (msg->type == PHP_HTTP_REQUEST) {
if (!php_http_message_header(msg, ZEND_STRL("Transfer-Encoding"))) {
/* no filter, no CR, no size, no TE, no CL */
if (0 <= php_http_select_str(msg->http.info.request.method, 3, "POST", "PUT", "PATCH")) {
/* quoting RFC7230#section-3.3.2
A user agent SHOULD send a Content-Length in a request message when
no Transfer-Encoding is sent and the request method defines a meaning
for an enclosed payload body. For example, a Content-Length header
field is normally sent in a POST request even when the value is 0
(indicating an empty payload body). A user agent SHOULD NOT send a
Content-Length header field when the request message does not contain
a payload body and the method semantics do not anticipate such a
body.
*/
ZVAL_LONG(&h, 0);
zend_hash_str_update(&msg->hdrs, "Content-Length", lenof("Content-Length"), &h);
}
}
}
}
static void message_headers(php_http_message_t *msg, php_http_buffer_t *str)
{
char *tmp = NULL;
switch (msg->type) {
case PHP_HTTP_REQUEST:
php_http_buffer_appendf(str, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
PTR_FREE(tmp);
break;
case PHP_HTTP_RESPONSE:
php_http_buffer_appendf(str, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&msg->http, tmp, PHP_HTTP_CRLF));
PTR_FREE(tmp);
break;
default:
break;
}
php_http_message_update_headers(msg);
php_http_header_to_string(str, &msg->hdrs);
}
void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg)
{
php_http_buffer_t str;
php_http_buffer_init_ex(&str, 0x1000, 0);
message_headers(msg, &str);
cb(cb_arg, str.data, str.used);
php_http_buffer_dtor(&str);
if (php_http_message_body_size(msg->body)) {
cb(cb_arg, ZEND_STRL(PHP_HTTP_CRLF));
php_http_message_body_to_callback(msg->body, cb, cb_arg, 0, 0);
}
}
void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length)
{
php_http_buffer_t str;
char *data;
php_http_buffer_init_ex(&str, 0x1000, 0);
message_headers(msg, &str);
if (php_http_message_body_size(msg->body)) {
php_http_buffer_appends(&str, PHP_HTTP_CRLF);
php_http_message_body_to_callback(msg->body, (php_http_pass_callback_t) php_http_buffer_append, &str, 0, 0);
}
data = php_http_buffer_data(&str, string, length);
if (!string) {
efree(data);
}
php_http_buffer_dtor(&str);
}
void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length)
{
char *buf;
php_http_buffer_t str;
php_http_message_t *msg;
php_http_buffer_init(&str);
msg = message = php_http_message_reverse(message);
do {
php_http_message_to_callback(message, (php_http_pass_callback_t) php_http_buffer_append, &str);
php_http_buffer_appends(&str, PHP_HTTP_CRLF);
} while ((message = message->parent));
php_http_message_reverse(msg);
buf = php_http_buffer_data(&str, string, length);
if (!string) {
efree(buf);
}
php_http_buffer_dtor(&str);
}
php_http_message_t *php_http_message_reverse(php_http_message_t *msg)
{
size_t i, c = php_http_message_count(msg);
if (c > 1) {
php_http_message_t *tmp = msg, **arr;
arr = ecalloc(c, sizeof(**arr));
for (i = 0; i < c; ++i) {
arr[i] = tmp;
tmp = tmp->parent;
}
arr[0]->parent = NULL;
for (i = 0; i < c-1; ++i) {
arr[i+1]->parent = arr[i];
}
msg = arr[c-1];
efree(arr);
}
return msg;
}
php_http_message_t *php_http_message_zip(php_http_message_t *dst, php_http_message_t *src)
{
php_http_message_t *tmp_dst, *tmp_src, *ret = dst;
while (dst && src) {
tmp_dst = dst->parent;
tmp_src = src->parent;
dst->parent = src;
if (tmp_dst) {
src->parent = tmp_dst;
}
src = tmp_src;
dst = tmp_dst;
}
return ret;
}
php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents)
{
php_http_message_t *temp, *copy = NULL;
php_http_info_t info;
if (from) {
info.type = from->type;
info.http = from->http;
copy = temp = php_http_message_init(to, 0, php_http_message_body_copy(from->body, NULL));
php_http_message_set_info(temp, &info);
zend_hash_copy(&temp->hdrs, &from->hdrs, (copy_ctor_func_t) zval_add_ref);
if (parents) while (from->parent) {
info.type = from->parent->type;
info.http = from->parent->http;
temp->parent = php_http_message_init(NULL, 0, php_http_message_body_copy(from->parent->body, NULL));
php_http_message_set_info(temp->parent, &info);
array_copy(&from->parent->hdrs, &temp->parent->hdrs);
temp = temp->parent;
from = from->parent;
}
}
return copy;
}
void php_http_message_dtor(php_http_message_t *message)
{
if (message) {
zend_hash_destroy(&message->hdrs);
php_http_message_body_free(&message->body);
switch (message->type) {
case PHP_HTTP_REQUEST:
PTR_SET(message->http.info.request.method, NULL);
PTR_SET(message->http.info.request.url, NULL);
break;
case PHP_HTTP_RESPONSE:
PTR_SET(message->http.info.response.status, NULL);
break;
default:
break;
}
}
}
void php_http_message_free(php_http_message_t **message)
{
if (*message) {
if ((*message)->parent) {
php_http_message_free(&(*message)->parent);
}
php_http_message_dtor(*message);
efree(*message);
*message = NULL;
}
}
static zend_class_entry *php_http_message_class_entry;
zend_class_entry *php_http_message_get_class_entry(void)
{
return php_http_message_class_entry;
}
static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *rv);
static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot);
static zend_object_handlers php_http_message_object_handlers;
static HashTable php_http_message_object_prophandlers;
static void php_http_message_object_prophandler_hash_dtor(zval *pData)
{
pefree(Z_PTR_P(pData), 1);
}
typedef void (*php_http_message_object_prophandler_func_t)(php_http_message_object_t *o, zval *v);
typedef struct php_http_message_object_prophandler {
php_http_message_object_prophandler_func_t read;
php_http_message_object_prophandler_func_t write;
} php_http_message_object_prophandler_t;
static ZEND_RESULT_CODE php_http_message_object_add_prophandler(const char *prop_str, size_t prop_len, php_http_message_object_prophandler_func_t read, php_http_message_object_prophandler_func_t write) {
php_http_message_object_prophandler_t h = { read, write };
if (!zend_hash_str_add_mem(&php_http_message_object_prophandlers, prop_str, prop_len, (void *) &h, sizeof(h))) {
return FAILURE;
}
return SUCCESS;
}
static php_http_message_object_prophandler_t *php_http_message_object_get_prophandler(zend_string *name_str) {
return zend_hash_str_find_ptr(&php_http_message_object_prophandlers, name_str->val, name_str->len);
}
static void php_http_message_object_prophandler_get_type(php_http_message_object_t *obj, zval *return_value) {
RETVAL_LONG(obj->message->type);
}
static void php_http_message_object_prophandler_set_type(php_http_message_object_t *obj, zval *value) {
php_http_message_set_type(obj->message, zval_get_long(value));
}
static void php_http_message_object_prophandler_get_request_method(php_http_message_object_t *obj, zval *return_value) {
if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.method) {
RETVAL_STRING(obj->message->http.info.request.method);
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_request_method(php_http_message_object_t *obj, zval *value) {
if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
zend_string *zs = zval_get_string(value);
PTR_SET(obj->message->http.info.request.method, estrndup(zs->val, zs->len));
zend_string_release(zs);
}
}
static void php_http_message_object_prophandler_get_request_url(php_http_message_object_t *obj, zval *return_value) {
char *url_str;
size_t url_len;
if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message) && obj->message->http.info.request.url && php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0)) {
RETVAL_STR(php_http_cs2zs(url_str, url_len));
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_request_url(php_http_message_object_t *obj, zval *value) {
if (PHP_HTTP_MESSAGE_TYPE(REQUEST, obj->message)) {
PTR_SET(obj->message->http.info.request.url, php_http_url_from_zval(value, ~0));
}
}
static void php_http_message_object_prophandler_get_response_status(php_http_message_object_t *obj, zval *return_value) {
if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message) && obj->message->http.info.response.status) {
RETVAL_STRING(obj->message->http.info.response.status);
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_response_status(php_http_message_object_t *obj, zval *value) {
if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
zend_string *zs = zval_get_string(value);
PTR_SET(obj->message->http.info.response.status, estrndup(zs->val, zs->len));
zend_string_release(zs);
}
}
static void php_http_message_object_prophandler_get_response_code(php_http_message_object_t *obj, zval *return_value) {
if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
RETVAL_LONG(obj->message->http.info.response.code);
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_response_code(php_http_message_object_t *obj, zval *value) {
if (PHP_HTTP_MESSAGE_TYPE(RESPONSE, obj->message)) {
obj->message->http.info.response.code = zval_get_long(value);
PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(obj->message->http.info.response.code)));
}
}
static void php_http_message_object_prophandler_get_http_version(php_http_message_object_t *obj, zval *return_value) {
char *version_str;
size_t version_len;
php_http_version_to_string(&obj->message->http.version, &version_str, &version_len, NULL, NULL);
RETVAL_STR(php_http_cs2zs(version_str, version_len));
}
static void php_http_message_object_prophandler_set_http_version(php_http_message_object_t *obj, zval *value) {
zend_string *zs = zval_get_string(value);
php_http_version_parse(&obj->message->http.version, zs->val);
zend_string_release(zs);
}
static void php_http_message_object_prophandler_get_headers(php_http_message_object_t *obj, zval *return_value ) {
array_init(return_value);
array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
}
static void php_http_message_object_prophandler_set_headers(php_http_message_object_t *obj, zval *value) {
HashTable *headers;
zval *orig_value = value;
if (Z_TYPE_P(value) != IS_ARRAY && Z_TYPE_P(value) != IS_OBJECT) {
convert_to_array_ex(value);
}
headers = HASH_OF(value);
zend_hash_clean(&obj->message->hdrs);
array_copy(headers, &obj->message->hdrs);
if (orig_value != value) {
zval_ptr_dtor(value);
}
}
static void php_http_message_object_prophandler_get_body(php_http_message_object_t *obj, zval *return_value) {
if (obj->body) {
RETVAL_OBJECT(&obj->body->zo, 1);
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_body(php_http_message_object_t *obj, zval *value) {
php_http_message_object_set_body(obj, value);
}
static void php_http_message_object_prophandler_get_parent_message(php_http_message_object_t *obj, zval *return_value) {
if (obj->message->parent) {
RETVAL_OBJECT(&obj->parent->zo, 1);
} else {
RETVAL_NULL();
}
}
static void php_http_message_object_prophandler_set_parent_message(php_http_message_object_t *obj, zval *value) {
if (Z_TYPE_P(value) == IS_OBJECT && instanceof_function(Z_OBJCE_P(value), php_http_message_class_entry)) {
php_http_message_object_t *parent_obj = PHP_HTTP_OBJ(NULL, value);
if (obj->message->parent) {
zend_objects_store_del(&obj->parent->zo);
}
Z_ADDREF_P(value);
obj->parent = parent_obj;
obj->message->parent = parent_obj->message;
}
}
#define PHP_HTTP_MESSAGE_OBJECT_INIT(obj) \
do { \
if (!obj->message) { \
obj->message = php_http_message_init(NULL, 0, NULL); \
} \
} while(0)
void php_http_message_object_reverse(zval *zmsg, zval *return_value)
{
size_t i;
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, zmsg);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
/* count */
i = php_http_message_count(obj->message);
if (i > 1) {
php_http_message_object_t **objects;
int last;
objects = ecalloc(i, sizeof(**objects));
/* we are the first message */
objects[0] = obj;
/* fetch parents */
for (i = 1; obj->parent; ++i) {
objects[i] = obj = obj->parent;
}
/* reorder parents */
for (last = --i; i; --i) {
objects[i]->message->parent = objects[i-1]->message;
objects[i]->parent = objects[i-1];
}
objects[0]->message->parent = NULL;
objects[0]->parent = NULL;
/* add ref, because we previously have not been a parent message */
Z_ADDREF_P(zmsg);
/* no addref, because we've been a parent message previously */
RETVAL_OBJECT(&objects[last]->zo, 0);
efree(objects);
} else {
RETURN_ZVAL(zmsg, 1, 0);
}
}
void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top)
{
php_http_message_t *save_parent_msg = NULL;
php_http_message_object_t *save_parent_obj = NULL, *obj = PHP_HTTP_OBJ(NULL, this_ptr);
php_http_message_object_t *prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
if (!top) {
save_parent_obj = obj->parent;
save_parent_msg = obj->message->parent;
} else {
/* iterate to the most parent object */
while (obj->parent) {
obj = obj->parent;
}
}
/* prepend */
obj->parent = prepend_obj;
obj->message->parent = prepend_obj->message;
/* add ref */
Z_ADDREF_P(prepend);
if (!top) {
prepend_obj->parent = save_parent_obj;
prepend_obj->message->parent = save_parent_msg;
}
}
ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *msg_obj, zval *zbody)
{
php_stream *s;
zend_string *body_str;
php_http_message_body_t *body;
php_http_message_body_object_t *body_obj;
switch (Z_TYPE_P(zbody)) {
case IS_RESOURCE:
php_stream_from_zval_no_verify(s, zbody);
if (!s) {
php_http_throw(unexpected_val, "The stream is not a valid resource", NULL);
return FAILURE;
}
is_resource:
body = php_http_message_body_init(NULL, s);
if (!(body_obj = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), body))) {
php_http_message_body_free(&body);
return FAILURE;
}
break;
case IS_OBJECT:
if (instanceof_function(Z_OBJCE_P(zbody), php_http_get_message_body_class_entry())) {
Z_ADDREF_P(zbody);
body_obj = PHP_HTTP_OBJ(NULL, zbody);
break;
}
/* no break */
default:
body_str = zval_get_string(zbody);
s = php_stream_temp_new();
php_stream_write(s, body_str->val, body_str->len);
zend_string_release(body_str);
goto is_resource;
}
if (!body_obj->body) {
body_obj->body = php_http_message_body_init(NULL, NULL);
}
if (msg_obj->body) {
zend_objects_store_del(&msg_obj->body->zo);
}
if (msg_obj->message) {
php_http_message_body_free(&msg_obj->message->body);
msg_obj->message->body = body_obj->body;
} else {
msg_obj->message = php_http_message_init(NULL, 0, body_obj->body);
}
php_http_message_body_addref(body_obj->body);
msg_obj->body = body_obj;
return SUCCESS;
}
ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj)
{
php_http_message_body_addref(obj->message->body);
return php_http_new((void *) &obj->body, php_http_get_message_body_class_entry(), (php_http_new_t) php_http_message_body_object_new_ex, NULL, obj->message->body);
}
zend_object *php_http_message_object_new(zend_class_entry *ce)
{
return &php_http_message_object_new_ex(ce, NULL)->zo;
}
php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg)
{
php_http_message_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
if (msg) {
o->message = msg;
if (msg->parent) {
o->parent = php_http_message_object_new_ex(ce, msg->parent);
}
o->body = php_http_message_body_object_new_ex(php_http_get_message_body_class_entry(), php_http_message_body_init(&msg->body, NULL));
}
o->zo.handlers = &php_http_message_object_handlers;
return o;
}
zend_object *php_http_message_object_clone(zval *this_ptr)
{
php_http_message_object_t *new_obj = NULL;
php_http_message_object_t *old_obj = PHP_HTTP_OBJ(NULL, this_ptr);
new_obj = php_http_message_object_new_ex(old_obj->zo.ce, php_http_message_copy(old_obj->message, NULL));
zend_objects_clone_members(&new_obj->zo, &old_obj->zo);
return &new_obj->zo;
}
void php_http_message_object_free(zend_object *object)
{
php_http_message_object_t *o = PHP_HTTP_OBJ(object, NULL);
if (!Z_ISUNDEF(o->iterator)) {
zval_ptr_dtor(&o->iterator);
ZVAL_UNDEF(&o->iterator);
}
if (o->message) {
/* do NOT free recursivly */
php_http_message_dtor(o->message);
efree(o->message);
o->message = NULL;
}
if (o->parent) {
if (GC_REFCOUNT(&o->parent->zo) == 1) {
zend_objects_store_del(&o->parent->zo);
}
zend_objects_store_del(&o->parent->zo);
o->parent = NULL;
}
if (o->body) {
if (GC_REFCOUNT(&o->body->zo) == 1) {
zend_objects_store_del(&o->body->zo);
}
zend_objects_store_del(&o->body->zo);
o->body = NULL;
}
zend_object_std_dtor(object);
}
static zval *php_http_message_object_read_prop(zval *object, zval *member, int type, void **cache_slot, zval *tmp)
{
zval *return_value;
zend_string *member_name = zval_get_string(member);
php_http_message_object_prophandler_t *handler = php_http_message_object_get_prophandler(member_name);
if (!handler || type == BP_VAR_R || type == BP_VAR_IS) {
return_value = zend_get_std_object_handlers()->read_property(object, member, type, cache_slot, tmp);
if (handler) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
handler->read(obj, tmp);
zval_ptr_dtor(return_value);
ZVAL_COPY_VALUE(return_value, tmp);
}
zend_string_release(member_name);
return return_value;
} else {
php_property_proxy_t *proxy;
php_property_proxy_object_t *proxy_obj;
proxy = php_property_proxy_init(object, member_name);
proxy_obj = php_property_proxy_object_new_ex(NULL, proxy);
ZVAL_OBJ(tmp, &proxy_obj->zo);
zend_string_release(member_name);
return tmp;
}
}
static void php_http_message_object_write_prop(zval *object, zval *member, zval *value, void **cache_slot)
{
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
php_http_message_object_prophandler_t *handler;
zend_string *member_name = zval_get_string(member);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if ((handler = php_http_message_object_get_prophandler(member_name))) {
handler->write(obj, value);
} else {
zend_get_std_object_handlers()->write_property(object, member, value, cache_slot);
}
zend_string_release(member_name);
}
static HashTable *php_http_message_object_get_debug_info(zval *object, int *is_temp)
{
zval tmp;
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, object);
HashTable *props = zend_get_std_object_handlers()->get_properties(object);
char *ver_str, *url_str = NULL;
size_t ver_len, url_len = 0;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
*is_temp = 0;
#define UPDATE_PROP(name_str, action_with_tmp) \
do { \
zend_property_info *pi; \
if ((pi = zend_hash_str_find_ptr(&obj->zo.ce->properties_info, name_str, lenof(name_str)))) { \
action_with_tmp; \
zend_hash_update_ind(props, pi->name, &tmp); \
} \
} while(0)
UPDATE_PROP("type", ZVAL_LONG(&tmp, obj->message->type));
ver_len = spprintf(&ver_str, 0, "%u.%u", obj->message->http.version.major, obj->message->http.version.minor);
UPDATE_PROP("httpVersion", ZVAL_STR(&tmp, php_http_cs2zs(ver_str, ver_len)));
switch (obj->message->type) {
case PHP_HTTP_REQUEST:
UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
UPDATE_PROP("requestMethod", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.request.method)));
if (obj->message->http.info.request.url) {
php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
UPDATE_PROP("requestUrl", ZVAL_STR(&tmp, php_http_cs2zs(url_str, url_len)));
} else {
UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
}
break;
case PHP_HTTP_RESPONSE:
UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, obj->message->http.info.response.code));
UPDATE_PROP("responseStatus", ZVAL_STRING(&tmp, STR_PTR(obj->message->http.info.response.status)));
UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
break;
case PHP_HTTP_NONE:
default:
UPDATE_PROP("responseCode", ZVAL_LONG(&tmp, 0));
UPDATE_PROP("responseStatus", ZVAL_EMPTY_STRING(&tmp));
UPDATE_PROP("requestMethod", ZVAL_EMPTY_STRING(&tmp));
UPDATE_PROP("requestUrl", ZVAL_EMPTY_STRING(&tmp));
break;
}
UPDATE_PROP("headers",
array_init(&tmp);
array_copy(&obj->message->hdrs, Z_ARRVAL(tmp));
);
UPDATE_PROP("body",
if (obj->body) {
ZVAL_OBJECT(&tmp, &obj->body->zo, 1);
} else {
ZVAL_NULL(&tmp);
}
);
UPDATE_PROP("parentMessage",
if (obj->message->parent) {
ZVAL_OBJECT(&tmp, &obj->parent->zo, 1);
} else {
ZVAL_NULL(&tmp);
}
);
return props;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___construct, 0, 0, 0)
ZEND_ARG_INFO(0, message)
ZEND_ARG_INFO(0, greedy)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, __construct)
{
zend_bool greedy = 1;
zval *zmessage = NULL;
php_http_message_t *msg = NULL;
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!b", &zmessage, &greedy), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_message_class_entry(), &zeh);
if (zmessage && Z_TYPE_P(zmessage) == IS_RESOURCE) {
php_stream *s;
php_http_message_parser_t p;
zend_error_handling zeh;
zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh);
php_stream_from_zval(s, zmessage);
zend_restore_error_handling(&zeh);
if (s && php_http_message_parser_init(&p)) {
unsigned flags = (greedy ? PHP_HTTP_MESSAGE_PARSER_GREEDY : 0);
php_http_buffer_t buf;
php_http_buffer_init_ex(&buf, 0x1000, PHP_HTTP_BUFFER_INIT_PREALLOC);
if (PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE == php_http_message_parser_parse_stream(&p, &buf, s, flags, &msg)) {
if (!EG(exception)) {
php_http_throw(bad_message, "Could not parse message from stream", NULL);
}
}
php_http_buffer_dtor(&buf);
php_http_message_parser_dtor(&p);
}
if (!msg && !EG(exception)) {
php_http_throw(bad_message, "Empty message received from stream", NULL);
}
} else if (zmessage) {
zend_string *zs_msg = zval_get_string(zmessage);
msg = php_http_message_parse(NULL, zs_msg->val, zs_msg->len, greedy);
if (!msg && !EG(exception)) {
php_http_throw(bad_message, "Could not parse message: %.*s", MIN(25, zs_msg->len), zs_msg->val);
}
zend_string_release(zs_msg);
}
if (msg) {
php_http_message_dtor(obj->message);
obj->message = msg;
if (obj->message->parent) {
obj->parent = php_http_message_object_new_ex(obj->zo.ce, obj->message->parent);
}
}
zend_restore_error_handling(&zeh);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getBody, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getBody)
{
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (!obj->body) {
php_http_message_object_init_body_object(obj);
}
if (obj->body) {
RETVAL_OBJECT(&obj->body->zo, 1);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setBody, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setBody)
{
zval *zbody;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zbody, php_http_get_message_body_class_entry())) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_message_object_prophandler_set_body(obj, zbody);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addBody, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, body, http\\Message\\Body, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, addBody)
{
zval *new_body;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O", &new_body, php_http_get_message_body_class_entry())) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_message_body_object_t *new_obj = PHP_HTTP_OBJ(NULL, new_body);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_message_body_to_callback(new_obj->body, (php_http_pass_callback_t) php_http_message_body_append, obj->message->body, 0, 0);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeader, 0, 0, 1)
ZEND_ARG_INFO(0, header)
ZEND_ARG_INFO(0, into_class)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getHeader)
{
char *header_str;
size_t header_len;
zend_class_entry *header_ce = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|C!", &header_str, &header_len, &header_ce)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
zval *header;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if ((header = php_http_message_header(obj->message, header_str, header_len))) {
if (!header_ce) {
RETURN_ZVAL(header, 1, 0);
} else if (instanceof_function(header_ce, php_http_header_get_class_entry())) {
php_http_object_method_t cb;
zval argv[2];
ZVAL_STRINGL(&argv[0], header_str, header_len);
ZVAL_COPY(&argv[1], header);
object_init_ex(return_value, header_ce);
php_http_object_method_init(&cb, return_value, ZEND_STRL("__construct"));
php_http_object_method_call(&cb, return_value, NULL, 2, argv);
php_http_object_method_dtor(&cb);
zval_ptr_dtor(&argv[0]);
zval_ptr_dtor(&argv[1]);
return;
} else {
php_error_docref(NULL, E_WARNING, "Class '%s' is not as descendant of http\\Header", header_ce->name->val);
}
}
}
RETURN_FALSE;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHeaders, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getHeaders)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
array_init(return_value);
array_copy(&obj->message->hdrs, Z_ARRVAL_P(return_value));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeader, 0, 0, 1)
ZEND_ARG_INFO(0, header)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setHeader)
{
zval *zvalue = NULL;
char *name_str;
size_t name_len;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|z!", &name_str, &name_len, &zvalue)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (!zvalue) {
zend_symtable_str_del(&obj->message->hdrs, name, name_len);
} else {
Z_TRY_ADDREF_P(zvalue);
zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
}
efree(name);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHeaders, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, headers, 1)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setHeaders)
{
zval *new_headers = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a/!", &new_headers)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
zend_hash_clean(&obj->message->hdrs);
if (new_headers) {
array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, 0, ARRAY_JOIN_PRETTIFY|ARRAY_JOIN_STRONLY);
}
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeader, 0, 0, 2)
ZEND_ARG_INFO(0, header)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, addHeader)
{
zval *zvalue;
char *name_str;
size_t name_len;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "sz", &name_str, &name_len, &zvalue)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *name = php_http_pretty_key(estrndup(name_str, name_len), name_len, 1, 1);
zval *header;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
Z_TRY_ADDREF_P(zvalue);
if ((header = php_http_message_header(obj->message, name, name_len))) {
convert_to_array(header);
zend_hash_next_index_insert(Z_ARRVAL_P(header), zvalue);
} else {
zend_symtable_str_update(&obj->message->hdrs, name, name_len, zvalue);
}
efree(name);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_addHeaders, 0, 0, 1)
ZEND_ARG_ARRAY_INFO(0, headers, 0)
ZEND_ARG_INFO(0, append)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, addHeaders)
{
zval *new_headers;
zend_bool append = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "a|b", &new_headers, &append)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
array_join(Z_ARRVAL_P(new_headers), &obj->message->hdrs, append, ARRAY_JOIN_STRONLY|ARRAY_JOIN_PRETTIFY);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getType, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getType)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
RETURN_LONG(obj->message->type);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setType, 0, 0, 1)
ZEND_ARG_INFO(0, type)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setType)
{
zend_long type;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &type)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_message_set_type(obj->message, type);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getInfo, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getInfo)
{
if (SUCCESS == zend_parse_parameters_none()) {
char *str, *tmp = NULL;
size_t len;
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
switch (obj->message->type) {
case PHP_HTTP_REQUEST:
len = spprintf(&str, 0, PHP_HTTP_INFO_REQUEST_FMT_ARGS(&obj->message->http, tmp, ""));
PTR_FREE(tmp);
break;
case PHP_HTTP_RESPONSE:
len = spprintf(&str, 0, PHP_HTTP_INFO_RESPONSE_FMT_ARGS(&obj->message->http, tmp, ""));
PTR_FREE(tmp);
break;
default:
RETURN_NULL();
break;
}
RETVAL_STR(php_http_cs2zs(str, len));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setInfo, 0, 0, 1)
ZEND_ARG_INFO(0, http_info)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setInfo)
{
char *str;
size_t len;
php_http_message_object_t *obj;
php_http_info_t inf;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (!php_http_info_parse(&inf, str)) {
php_http_throw(bad_header, "Could not parse message info '%s'", str);
return;
}
php_http_message_set_info(obj->message, &inf);
php_http_info_dtor(&inf);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getHttpVersion, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getHttpVersion)
{
if (SUCCESS == zend_parse_parameters_none()) {
char *str;
size_t len;
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_version_to_string(&obj->message->http.version, &str, &len, NULL, NULL);
RETURN_STR(php_http_cs2zs(str, len));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setHttpVersion, 0, 0, 1)
ZEND_ARG_INFO(0, http_version)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setHttpVersion)
{
char *v_str;
size_t v_len;
php_http_version_t version;
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &v_str, &v_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_expect(php_http_version_parse(&version, v_str), unexpected_val, return);
obj->message->http.version = version;
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseCode, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getResponseCode)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_RESPONSE) {
php_error_docref(NULL, E_WARNING, "http\\Message is not if type response");
RETURN_FALSE;
}
RETURN_LONG(obj->message->http.info.response.code);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseCode, 0, 0, 1)
ZEND_ARG_INFO(0, response_code)
ZEND_ARG_INFO(0, strict)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setResponseCode)
{
zend_long code;
zend_bool strict = 1;
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "l|b", &code, &strict), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_RESPONSE) {
php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
return;
}
if (strict && (code < 100 || code > 599)) {
php_http_throw(invalid_arg, "Invalid response code (100-599): %ld", code);
return;
}
obj->message->http.info.response.code = code;
PTR_SET(obj->message->http.info.response.status, estrdup(php_http_env_get_response_status_for_code(code)));
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getResponseStatus, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getResponseStatus)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_RESPONSE) {
php_error_docref(NULL, E_WARNING, "http\\Message is not of type response");
}
if (obj->message->http.info.response.status) {
RETURN_STRING(obj->message->http.info.response.status);
} else {
RETURN_EMPTY_STRING();
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setResponseStatus, 0, 0, 1)
ZEND_ARG_INFO(0, response_status)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setResponseStatus)
{
char *status;
size_t status_len;
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &status, &status_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_RESPONSE) {
php_http_throw(bad_method_call, "http\\Message is not of type response", NULL);
}
PTR_SET(obj->message->http.info.response.status, estrndup(status, status_len));
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestMethod, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getRequestMethod)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_REQUEST) {
php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
RETURN_FALSE;
}
if (obj->message->http.info.request.method) {
RETURN_STRING(obj->message->http.info.request.method);
} else {
RETURN_EMPTY_STRING();
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestMethod, 0, 0, 1)
ZEND_ARG_INFO(0, request_method)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setRequestMethod)
{
char *method;
size_t method_len;
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &method, &method_len), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_REQUEST) {
php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
return;
}
if (method_len < 1) {
php_http_throw(invalid_arg, "Cannot set http\\Message's request method to an empty string", NULL);
return;
}
PTR_SET(obj->message->http.info.request.method, estrndup(method, method_len));
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getRequestUrl, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getRequestUrl)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_REQUEST) {
php_error_docref(NULL, E_WARNING, "http\\Message is not of type request");
RETURN_FALSE;
}
if (obj->message->http.info.request.url) {
char *url_str;
size_t url_len;
php_http_url_to_string(obj->message->http.info.request.url, &url_str, &url_len, 0);
RETURN_STR(php_http_cs2zs(url_str, url_len));
} else {
RETURN_EMPTY_STRING();
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_setRequestUrl, 0, 0, 1)
ZEND_ARG_INFO(0, url)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, setRequestUrl)
{
zval *zurl;
php_http_url_t *url;
php_http_message_object_t *obj;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", &zurl), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (obj->message->type != PHP_HTTP_REQUEST) {
php_http_throw(bad_method_call, "http\\Message is not of type request", NULL);
return;
}
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
url = php_http_url_from_zval(zurl, ~0);
zend_restore_error_handling(&zeh);
if (url && php_http_url_is_empty(url)) {
php_http_url_free(&url);
php_http_throw(invalid_arg, "Cannot set http\\Message's request url to an empty string", NULL);
} else if (url) {
PTR_SET(obj->message->http.info.request.url, url);
}
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_getParentMessage, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, getParentMessage)
{
php_http_message_object_t *obj;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (!obj->message->parent) {
php_http_throw(unexpected_val, "http\\Message has not parent message", NULL);
return;
}
RETVAL_OBJECT(&obj->parent->zo, 1);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage___toString, 0, 0, 0)
ZEND_END_ARG_INFO();
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toString, 0, 0, 0)
ZEND_ARG_INFO(0, include_parent)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, toString)
{
zend_bool include_parent = 0;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|b", &include_parent)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *string;
size_t length;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (include_parent) {
php_http_message_serialize(obj->message, &string, &length);
} else {
php_http_message_to_string(obj->message, &string, &length);
}
if (string) {
RETURN_STR(php_http_cs2zs(string, length));
}
}
RETURN_EMPTY_STRING();
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toStream, 0, 0, 1)
ZEND_ARG_INFO(0, stream)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, toStream)
{
zval *zstream;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "r", &zstream)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
php_stream *s;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_stream_from_zval(s, zstream);
php_http_message_to_callback(obj->message, (php_http_pass_callback_t) _php_stream_write, s);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_toCallback, 0, 0, 1)
ZEND_ARG_INFO(0, callback)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, toCallback)
{
php_http_pass_fcall_arg_t fcd;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "f", &fcd.fci, &fcd.fcc)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
ZVAL_COPY(&fcd.fcz, getThis());
php_http_message_to_callback(obj->message, php_http_pass_fcall_callback, &fcd);
zend_fcall_info_args_clear(&fcd.fci, 1);
zval_ptr_dtor(&fcd.fcz);
RETURN_ZVAL(getThis(), 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_serialize, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, serialize)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *string;
size_t length;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
php_http_message_serialize(obj->message, &string, &length);
RETURN_STR(php_http_cs2zs(string, length));
}
RETURN_EMPTY_STRING();
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, serialized)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, unserialize)
{
size_t length;
char *serialized;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &serialized, &length)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_message_t *msg;
if (obj->message) {
/* do not free recursively */
php_http_message_dtor(obj->message);
efree(obj->message);
}
if ((msg = php_http_message_parse(NULL, serialized, length, 1))) {
obj->message = msg;
} else {
obj->message = php_http_message_init(NULL, 0, NULL);
php_error_docref(NULL, E_ERROR, "Could not unserialize http\\Message");
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_detach, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, detach)
{
php_http_message_object_t *obj, *new_obj;
php_http_message_t *msg_cpy;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
msg_cpy = php_http_message_copy_ex(obj->message, NULL, 0);
new_obj = php_http_message_object_new_ex(obj->zo.ce, msg_cpy);
RETVAL_OBJ(&new_obj->zo);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_prepend, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, message, http\\Message, 0)
ZEND_ARG_INFO(0, top)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, prepend)
{
zval *prepend;
zend_bool top = 1;
php_http_message_t *msg[2];
php_http_message_object_t *obj, *prepend_obj;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "O|b", &prepend, php_http_message_class_entry, &top), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
prepend_obj = PHP_HTTP_OBJ(NULL, prepend);
PHP_HTTP_MESSAGE_OBJECT_INIT(prepend_obj);
/* safety check */
for (msg[0] = obj->message; msg[0]; msg[0] = msg[0]->parent) {
for (msg[1] = prepend_obj->message; msg[1]; msg[1] = msg[1]->parent) {
if (msg[0] == msg[1]) {
php_http_throw(unexpected_val, "Cannot prepend a message located within the same message chain", NULL);
return;
}
}
}
php_http_message_object_prepend(getThis(), prepend, top);
RETURN_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_reverse, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, reverse)
{
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
php_http_message_object_reverse(getThis(), return_value);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_isMultipart, 0, 0, 0)
ZEND_ARG_INFO(1, boundary)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, isMultipart)
{
zval *zboundary = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!", &zboundary)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
char *boundary = NULL;
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (php_http_message_is_multipart(obj->message, zboundary ? &boundary : NULL)) {
RETVAL_TRUE;
} else {
RETVAL_FALSE;
}
if (zboundary && boundary) {
ZVAL_DEREF(zboundary);
zval_dtor(zboundary);
ZVAL_STR(zboundary, php_http_cs2zs(boundary, strlen(boundary)));
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_splitMultipartBody, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, splitMultipartBody)
{
php_http_message_object_t *obj;
php_http_message_t *msg;
char *boundary = NULL;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
if (!php_http_message_is_multipart(obj->message, &boundary)) {
php_http_throw(bad_method_call, "http\\Message is not a multipart message", NULL);
return;
}
php_http_expect(msg = php_http_message_body_split(obj->message->body, boundary), bad_message, return);
PTR_FREE(boundary);
RETURN_OBJ(&php_http_message_object_new_ex(obj->zo.ce, msg)->zo);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_count, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, count)
{
zend_long count_mode = -1;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &count_mode)) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
PHP_HTTP_MESSAGE_OBJECT_INIT(obj);
RETURN_LONG(php_http_message_count(obj->message));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_rewind, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, rewind)
{
if (SUCCESS == zend_parse_parameters_none()) {
zval *zobj = getThis();
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (!Z_ISUNDEF(obj->iterator)) {
zval_ptr_dtor(&obj->iterator);
}
ZVAL_COPY(&obj->iterator, zobj);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_valid, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, valid)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
RETURN_BOOL(!Z_ISUNDEF(obj->iterator));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_next, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, next)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (!Z_ISUNDEF(obj->iterator)) {
php_http_message_object_t *itr = PHP_HTTP_OBJ(NULL, &obj->iterator);
if (itr->parent) {
zval tmp;
ZVAL_OBJECT(&tmp, &itr->parent->zo, 1);
zval_ptr_dtor(&obj->iterator);
obj->iterator = tmp;
} else {
zval_ptr_dtor(&obj->iterator);
ZVAL_UNDEF(&obj->iterator);
}
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_key, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, key)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
RETURN_LONG(Z_ISUNDEF(obj->iterator) ? 0 : Z_OBJ_HANDLE(obj->iterator));
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessage_current, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessage, current)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_message_object_t *obj = PHP_HTTP_OBJ(NULL, getThis());
if (!Z_ISUNDEF(obj->iterator)) {
RETURN_ZVAL(&obj->iterator, 1, 0);
}
}
}
static zend_function_entry php_http_message_methods[] = {
PHP_ME(HttpMessage, __construct, ai_HttpMessage___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpMessage, getBody, ai_HttpMessage_getBody, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setBody, ai_HttpMessage_setBody, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, addBody, ai_HttpMessage_addBody, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getHeader, ai_HttpMessage_getHeader, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setHeader, ai_HttpMessage_setHeader, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, addHeader, ai_HttpMessage_addHeader, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getHeaders, ai_HttpMessage_getHeaders, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setHeaders, ai_HttpMessage_setHeaders, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, addHeaders, ai_HttpMessage_addHeaders, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getType, ai_HttpMessage_getType, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setType, ai_HttpMessage_setType, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getInfo, ai_HttpMessage_getInfo, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setInfo, ai_HttpMessage_setInfo, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getResponseCode, ai_HttpMessage_getResponseCode, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setResponseCode, ai_HttpMessage_setResponseCode, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getResponseStatus, ai_HttpMessage_getResponseStatus, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setResponseStatus, ai_HttpMessage_setResponseStatus, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getRequestMethod, ai_HttpMessage_getRequestMethod, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setRequestMethod, ai_HttpMessage_setRequestMethod, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getRequestUrl, ai_HttpMessage_getRequestUrl, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setRequestUrl, ai_HttpMessage_setRequestUrl, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getHttpVersion, ai_HttpMessage_getHttpVersion, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, setHttpVersion, ai_HttpMessage_setHttpVersion, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, getParentMessage, ai_HttpMessage_getParentMessage, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, toString, ai_HttpMessage_toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, toCallback, ai_HttpMessage_toCallback, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, toStream, ai_HttpMessage_toStream, ZEND_ACC_PUBLIC)
/* implements Countable */
PHP_ME(HttpMessage, count, ai_HttpMessage_count, ZEND_ACC_PUBLIC)
/* implements Serializable */
PHP_ME(HttpMessage, serialize, ai_HttpMessage_serialize, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, unserialize, ai_HttpMessage_unserialize, ZEND_ACC_PUBLIC)
/* implements Iterator */
PHP_ME(HttpMessage, rewind, ai_HttpMessage_rewind, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, valid, ai_HttpMessage_valid, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, current, ai_HttpMessage_current, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, key, ai_HttpMessage_key, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, next, ai_HttpMessage_next, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpMessage, __toString, toString, ai_HttpMessage___toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, detach, ai_HttpMessage_detach, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, prepend, ai_HttpMessage_prepend, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, reverse, ai_HttpMessage_reverse, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, isMultipart, ai_HttpMessage_isMultipart, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessage, splitMultipartBody, ai_HttpMessage_splitMultipartBody, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_message)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Message", php_http_message_methods);
php_http_message_class_entry = zend_register_internal_class(&ce);
php_http_message_class_entry->create_object = php_http_message_object_new;
memcpy(&php_http_message_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_message_object_handlers.offset = XtOffsetOf(php_http_message_object_t, zo);
php_http_message_object_handlers.clone_obj = php_http_message_object_clone;
php_http_message_object_handlers.free_obj = php_http_message_object_free;
php_http_message_object_handlers.read_property = php_http_message_object_read_prop;
php_http_message_object_handlers.write_property = php_http_message_object_write_prop;
php_http_message_object_handlers.get_debug_info = php_http_message_object_get_debug_info;
php_http_message_object_handlers.get_property_ptr_ptr = NULL;
zend_class_implements(php_http_message_class_entry, 3, spl_ce_Countable, zend_ce_serializable, zend_ce_iterator);
zend_hash_init(&php_http_message_object_prophandlers, 9, NULL, php_http_message_object_prophandler_hash_dtor, 1);
zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("type"), PHP_HTTP_NONE, ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("type"), php_http_message_object_prophandler_get_type, php_http_message_object_prophandler_set_type);
zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("body"), ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("body"), php_http_message_object_prophandler_get_body, php_http_message_object_prophandler_set_body);
zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestMethod"), "", ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("requestMethod"), php_http_message_object_prophandler_get_request_method, php_http_message_object_prophandler_set_request_method);
zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("requestUrl"), "", ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("requestUrl"), php_http_message_object_prophandler_get_request_url, php_http_message_object_prophandler_set_request_url);
zend_declare_property_string(php_http_message_class_entry, ZEND_STRL("responseStatus"), "", ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("responseStatus"), php_http_message_object_prophandler_get_response_status, php_http_message_object_prophandler_set_response_status);
zend_declare_property_long(php_http_message_class_entry, ZEND_STRL("responseCode"), 0, ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("responseCode"), php_http_message_object_prophandler_get_response_code, php_http_message_object_prophandler_set_response_code);
zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("httpVersion"), ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("httpVersion"), php_http_message_object_prophandler_get_http_version, php_http_message_object_prophandler_set_http_version);
zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("headers"), ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("headers"), php_http_message_object_prophandler_get_headers, php_http_message_object_prophandler_set_headers);
zend_declare_property_null(php_http_message_class_entry, ZEND_STRL("parentMessage"), ZEND_ACC_PROTECTED);
php_http_message_object_add_prophandler(ZEND_STRL("parentMessage"), php_http_message_object_prophandler_get_parent_message, php_http_message_object_prophandler_set_parent_message);
zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_NONE"), PHP_HTTP_NONE);
zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_REQUEST"), PHP_HTTP_REQUEST);
zend_declare_class_constant_long(php_http_message_class_entry, ZEND_STRL("TYPE_RESPONSE"), PHP_HTTP_RESPONSE);
return SUCCESS;
}
PHP_MSHUTDOWN_FUNCTION(http_message)
{
zend_hash_destroy(&php_http_message_object_prophandlers);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message.h 0000644 0001750 0000144 00000011313 12667772426 016655 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_MESSAGE_H
#define PHP_HTTP_MESSAGE_H
#include "php_http_message_body.h"
#include "php_http_header.h"
/* required minimum length of an HTTP message "HTTP/1.1" */
#define PHP_HTTP_MESSAGE_MIN_SIZE 8
#define PHP_HTTP_MESSAGE_TYPE(TYPE, msg) ((msg) && ((msg)->type == PHP_HTTP_ ##TYPE))
typedef php_http_info_type_t php_http_message_type_t;
typedef struct php_http_message php_http_message_t;
struct php_http_message {
PHP_HTTP_INFO_IMPL(http, type)
HashTable hdrs;
php_http_message_body_t *body;
php_http_message_t *parent;
void *opaque;
};
PHP_HTTP_API zend_bool php_http_message_info_callback(php_http_message_t **message, HashTable **headers, php_http_info_t *info);
PHP_HTTP_API php_http_message_t *php_http_message_init(php_http_message_t *m, php_http_message_type_t t, php_http_message_body_t *body);
PHP_HTTP_API php_http_message_t *php_http_message_init_env(php_http_message_t *m, php_http_message_type_t t);
PHP_HTTP_API php_http_message_t *php_http_message_copy_ex(php_http_message_t *from, php_http_message_t *to, zend_bool parents);
static inline php_http_message_t *php_http_message_copy(php_http_message_t *from, php_http_message_t *to)
{
return php_http_message_copy_ex(from, to, 1);
}
PHP_HTTP_API void php_http_message_dtor(php_http_message_t *message);
PHP_HTTP_API void php_http_message_free(php_http_message_t **message);
PHP_HTTP_API void php_http_message_set_type(php_http_message_t *m, php_http_message_type_t t);
PHP_HTTP_API void php_http_message_set_info(php_http_message_t *message, php_http_info_t *info);
PHP_HTTP_API void php_http_message_update_headers(php_http_message_t *msg);
PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, const char *key_str, size_t key_len);
static inline zend_string *php_http_message_header_string(php_http_message_t *msg, const char *key_str, size_t key_len)
{
zval *header;
if ((header = php_http_message_header(msg, key_str, key_len))) {
return php_http_header_value_to_string(header);
}
return NULL;
}
PHP_HTTP_API zend_bool php_http_message_is_multipart(php_http_message_t *msg, char **boundary);
PHP_HTTP_API void php_http_message_to_string(php_http_message_t *msg, char **string, size_t *length);
PHP_HTTP_API void php_http_message_to_struct(php_http_message_t *msg, zval *strct);
PHP_HTTP_API void php_http_message_to_callback(php_http_message_t *msg, php_http_pass_callback_t cb, void *cb_arg);
PHP_HTTP_API void php_http_message_serialize(php_http_message_t *message, char **string, size_t *length);
PHP_HTTP_API php_http_message_t *php_http_message_reverse(php_http_message_t *msg);
PHP_HTTP_API php_http_message_t *php_http_message_zip(php_http_message_t *one, php_http_message_t *two);
static inline size_t php_http_message_count(php_http_message_t *m)
{
size_t c = 1;
while ((m = m->parent)) {
++c;
}
return c;
}
PHP_HTTP_API php_http_message_t *php_http_message_parse(php_http_message_t *msg, const char *str, size_t len, zend_bool greedy);
typedef struct php_http_message_object {
php_http_message_t *message;
struct php_http_message_object *parent;
php_http_message_body_object_t *body;
zval iterator;
zend_object zo;
} php_http_message_object_t;
PHP_HTTP_API zend_class_entry *php_http_message_get_class_entry(void);
PHP_MINIT_FUNCTION(http_message);
PHP_MSHUTDOWN_FUNCTION(http_message);
void php_http_message_object_prepend(zval *this_ptr, zval *prepend, zend_bool top /* = 1 */);
void php_http_message_object_reverse(zval *this_ptr, zval *return_value);
ZEND_RESULT_CODE php_http_message_object_set_body(php_http_message_object_t *obj, zval *zbody);
ZEND_RESULT_CODE php_http_message_object_init_body_object(php_http_message_object_t *obj);
zend_object *php_http_message_object_new(zend_class_entry *ce);
php_http_message_object_t *php_http_message_object_new_ex(zend_class_entry *ce, php_http_message_t *msg);
zend_object *php_http_message_object_clone(zval *object);
void php_http_message_object_free(zend_object *object);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message_parser.c 0000644 0001750 0000144 00000060041 12667772426 020226 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#ifndef DBG_PARSER
# define DBG_PARSER 0
#endif
typedef struct php_http_message_parser_state_spec {
php_http_message_parser_state_t state;
unsigned need_data:1;
} php_http_message_parser_state_spec_t;
static const php_http_message_parser_state_spec_t php_http_message_parser_states[] = {
{PHP_HTTP_MESSAGE_PARSER_STATE_START, 1},
{PHP_HTTP_MESSAGE_PARSER_STATE_HEADER, 0},
{PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE, 0},
{PHP_HTTP_MESSAGE_PARSER_STATE_BODY, 0},
{PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB, 1},
{PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, 1},
{PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, 1},
{PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, 0},
{PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, 0},
{PHP_HTTP_MESSAGE_PARSER_STATE_DONE, 0}
};
#if DBG_PARSER
const char *php_http_message_parser_state_name(php_http_message_parser_state_t state) {
const char *states[] = {"START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "UPDATE_CL", "DONE"};
if (state < 0 || state > (sizeof(states)/sizeof(char*))-1) {
return "FAILURE";
}
return states[state];
}
#endif
php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser)
{
if (!parser) {
parser = emalloc(sizeof(*parser));
}
memset(parser, 0, sizeof(*parser));
php_http_header_parser_init(&parser->header);
return parser;
}
php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...)
{
php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
va_list va_args;
unsigned i;
if (argc > 0) {
/* short circuit */
ZEND_PTR_STACK_RESIZE_IF_NEEDED((&parser->stack), argc);
va_start(va_args, argc);
for (i = 0; i < argc; ++i) {
state = va_arg(va_args, php_http_message_parser_state_t);
zend_ptr_stack_push(&parser->stack, (void *) state);
}
va_end(va_args);
}
return state;
}
php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser)
{
if (parser->stack.top) {
return (php_http_message_parser_state_t) parser->stack.elements[parser->stack.top - 1];
}
return PHP_HTTP_MESSAGE_PARSER_STATE_START;
}
php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser)
{
if (parser->stack.top) {
return (php_http_message_parser_state_t) zend_ptr_stack_pop(&parser->stack);
}
return PHP_HTTP_MESSAGE_PARSER_STATE_START;
}
void php_http_message_parser_dtor(php_http_message_parser_t *parser)
{
php_http_header_parser_dtor(&parser->header);
zend_ptr_stack_destroy(&parser->stack);
php_http_message_free(&parser->message);
if (parser->dechunk) {
php_http_encoding_stream_free(&parser->dechunk);
}
if (parser->inflate) {
php_http_encoding_stream_free(&parser->inflate);
}
}
void php_http_message_parser_free(php_http_message_parser_t **parser)
{
if (*parser) {
php_http_message_parser_dtor(*parser);
efree(*parser);
*parser = NULL;
}
}
php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, php_http_message_t **message)
{
php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START;
if (!buf->data) {
php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
}
while (1) {
size_t justread = 0;
#if DBG_PARSER
fprintf(stderr, "#SP: %s (f:%u)\n", php_http_message_parser_state_name(state), flags);
#endif
/* resize if needed */
if (buf->free < 0x1000) {
php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
}
switch (state) {
case PHP_HTTP_MESSAGE_PARSER_STATE_START:
case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER:
case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE:
/* read line */
php_stream_get_line(s, buf->data + buf->used, buf->free, &justread);
/* if we fail reading a whole line, try a single char */
if (!justread) {
int c = php_stream_getc(s);
if (c != EOF) {
char s[1] = {c};
justread = php_http_buffer_append(buf, s, 1);
}
}
php_http_buffer_account(buf, justread);
break;
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB:
/* read all */
justread = php_stream_read(s, buf->data + buf->used, buf->free);
php_http_buffer_account(buf, justread);
break;
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH:
/* read body_length */
justread = php_stream_read(s, buf->data + buf->used, MIN(buf->free, parser->body_length));
php_http_buffer_account(buf, justread);
break;
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED:
/* duh, this is very naive */
if (parser->body_length) {
justread = php_stream_read(s, buf->data + buf->used, MIN(parser->body_length, buf->free));
php_http_buffer_account(buf, justread);
parser->body_length -= justread;
} else {
php_http_buffer_resize(buf, 24);
php_stream_get_line(s, buf->data, buf->free, &justread);
php_http_buffer_account(buf, justread);
parser->body_length = strtoul(buf->data + buf->used - justread, NULL, 16);
}
break;
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY:
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:
case PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL:
/* should not occur */
abort();
break;
case PHP_HTTP_MESSAGE_PARSER_STATE_DONE:
case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
return php_http_message_parser_state_is(parser);
}
if (justread) {
state = php_http_message_parser_parse(parser, buf, flags, message);
} else if (php_stream_eof(s)) {
return php_http_message_parser_parse(parser, buf, flags | PHP_HTTP_MESSAGE_PARSER_CLEANUP, message);
} else {
return state;
}
}
return PHP_HTTP_MESSAGE_PARSER_STATE_DONE;
}
php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message)
{
char *str = NULL;
size_t len = 0;
size_t cut = 0;
while (buffer->used || !php_http_message_parser_states[php_http_message_parser_state_is(parser)].need_data) {
#if DBG_PARSER
fprintf(stderr, "#MP: %s (f: %u, t:%d, l:%zu)\n",
php_http_message_parser_state_name(php_http_message_parser_state_is(parser)),
flags,
message && *message ? (*message)->type : -1,
buffer->used
);
_dpf(0, buffer->data, buffer->used);
#endif
switch (php_http_message_parser_state_pop(parser))
{
case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
case PHP_HTTP_MESSAGE_PARSER_STATE_START:
{
char *ptr = buffer->data;
while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
++ptr;
}
php_http_buffer_cut(buffer, 0, ptr - buffer->data);
if (buffer->used) {
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
}
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER:
{
unsigned header_parser_flags = (flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP) ? PHP_HTTP_HEADER_PARSER_CLEANUP : 0;
switch (php_http_header_parser_parse(&parser->header, buffer, header_parser_flags, *message ? &(*message)->hdrs : NULL, (php_http_info_callback_t) php_http_message_info_callback, message)) {
case PHP_HTTP_HEADER_PARSER_STATE_FAILURE:
return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
case PHP_HTTP_HEADER_PARSER_STATE_DONE:
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
break;
default:
if (buffer->used || !(flags & PHP_HTTP_MESSAGE_PARSER_CLEANUP)) {
return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
} else {
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
}
}
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE:
{
zval h, *h_ptr, *h_loc = NULL, *h_con = NULL, *h_ce;
zend_bool chunked = 0;
zend_long content_length = -1;
zend_string *content_range = NULL;
/* Content-Range has higher precedence than Content-Length,
* and content-length denotes the original length of the entity,
* so let's *NOT* remove CR/CL, because that would fundamentally
* change the meaning of the whole message
*/
if ((h_ptr = php_http_message_header(*message, ZEND_STRL("Transfer-Encoding")))) {
zend_string *zs = zval_get_string(h_ptr);
chunked = zend_string_equals_literal(zs, "chunked");
zend_string_release(zs);
Z_TRY_ADDREF_P(h_ptr);
zend_hash_str_update(&(*message)->hdrs, "X-Original-Transfer-Encoding", lenof("X-Original-Transfer-Encoding"), h_ptr);
zend_hash_str_del(&(*message)->hdrs, "Transfer-Encoding", lenof("Transfer-Encoding"));
/* reset */
ZVAL_LONG(&h, 0);
zend_hash_str_update(&(*message)->hdrs, "Content-Length", lenof("Content-Length"), &h);
} else if ((h_ptr = php_http_message_header(*message, ZEND_STRL("Content-Length")))) {
content_length = zval_get_long(h_ptr);
Z_TRY_ADDREF_P(h_ptr);
zend_hash_str_update(&(*message)->hdrs, "X-Original-Content-Length", lenof("X-Original-Content-Length"), h_ptr);
}
if ((content_range = php_http_message_header_string(*message, ZEND_STRL("Content-Range")))) {
ZVAL_STR_COPY(&h, content_range);
zend_hash_str_update(&(*message)->hdrs, "Content-Range", lenof("Content-Range"), &h);
}
/* so, if curl sees a 3xx code, a Location header and a Connection:close header
* it decides not to read the response body.
*/
if ((flags & PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS)
&& (*message)->type == PHP_HTTP_RESPONSE
&& (*message)->http.info.response.code/100 == 3
&& (h_loc = php_http_message_header(*message, ZEND_STRL("Location")))
&& (h_con = php_http_message_header(*message, ZEND_STRL("Connection")))
) {
zend_string *con = zval_get_string(h_con);
if (php_http_match(con->val, "close", PHP_HTTP_MATCH_WORD)) {
zend_string_release(con);
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
break;
}
zend_string_release(con);
}
if ((h_ce = php_http_message_header(*message, ZEND_STRL("Content-Encoding")))) {
zend_string *ce = zval_get_string(h_ce);
if (php_http_match(ce->val, "gzip", PHP_HTTP_MATCH_WORD)
|| php_http_match(ce->val, "x-gzip", PHP_HTTP_MATCH_WORD)
|| php_http_match(ce->val, "deflate", PHP_HTTP_MATCH_WORD)
) {
if (parser->inflate) {
php_http_encoding_stream_reset(&parser->inflate);
} else {
parser->inflate = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), 0);
}
Z_TRY_ADDREF_P(h_ce);
zend_hash_str_update(&(*message)->hdrs, "X-Original-Content-Encoding", lenof("X-Original-Content-Encoding"), h_ce);
zend_hash_str_del(&(*message)->hdrs, "Content-Encoding", lenof("Content-Encoding"));
}
zend_string_release(ce);
}
if ((flags & PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES)) {
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
} else {
if (chunked) {
parser->dechunk = php_http_encoding_stream_init(parser->dechunk, php_http_encoding_stream_get_dechunk_ops(), 0);
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
break;
}
if (content_range) {
ulong total = 0, start = 0, end = 0;
if (!strncasecmp(content_range->val, "bytes", lenof("bytes"))
&& ( content_range->val[lenof("bytes")] == ':'
|| content_range->val[lenof("bytes")] == ' '
|| content_range->val[lenof("bytes")] == '='
)
) {
char *total_at = NULL, *end_at = NULL;
char *start_at = content_range->val + sizeof("bytes");
start = strtoul(start_at, &end_at, 10);
if (end_at) {
end = strtoul(end_at + 1, &total_at, 10);
if (total_at && strncmp(total_at + 1, "*", 1)) {
total = strtoul(total_at + 1, NULL, 10);
}
if (end >= start && (!total || end <= total)) {
parser->body_length = end + 1 - start;
php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
zend_string_release(content_range);
break;
}
}
}
zend_string_release(content_range);
}
if (content_length >= 0) {
parser->body_length = content_length;
php_http_message_parser_state_push(parser, 1, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
break;
}
if ((*message)->type == PHP_HTTP_REQUEST) {
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
} else {
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
}
}
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY:
{
if (len) {
if (parser->inflate) {
char *dec_str = NULL;
size_t dec_len;
if (SUCCESS != php_http_encoding_stream_update(parser->inflate, str, len, &dec_str, &dec_len)) {
return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
}
if (str != buffer->data) {
PTR_FREE(str);
}
str = dec_str;
len = dec_len;
}
php_stream_write(php_http_message_body_stream((*message)->body), str, len);
}
if (cut) {
php_http_buffer_cut(buffer, 0, cut);
}
if (str != buffer->data) {
PTR_FREE(str);
}
str = NULL;
len = 0;
cut = 0;
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB:
{
str = buffer->data;
len = buffer->used;
cut = len;
php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH:
{
len = MIN(parser->body_length, buffer->used);
str = buffer->data;
cut = len;
parser->body_length -= len;
php_http_message_parser_state_push(parser, 2, !parser->body_length?PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED:
{
/*
* - pass available data through the dechunk stream
* - pass decoded data along
* - if stream zeroed:
* Y: - cut processed string out of buffer, but leave length of unprocessed dechunk stream data untouched
* - body done
* N: - parse ahaed
*/
char *dec_str = NULL;
size_t dec_len;
if (SUCCESS != php_http_encoding_stream_update(parser->dechunk, buffer->data, buffer->used, &dec_str, &dec_len)) {
return PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE;
}
str = dec_str;
len = dec_len;
if (php_http_encoding_stream_done(parser->dechunk)) {
cut = buffer->used - PHP_HTTP_BUFFER(parser->dechunk->ctx)->used;
php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
} else {
cut = buffer->used;
php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
}
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:
{
php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
if (parser->dechunk && parser->dechunk->ctx) {
char *dec_str = NULL;
size_t dec_len;
if (SUCCESS != php_http_encoding_stream_finish(parser->dechunk, &dec_str, &dec_len)) {
return php_http_message_parser_state_push(parser, 1, PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
}
php_http_encoding_stream_dtor(parser->dechunk);
if (dec_str && dec_len) {
str = dec_str;
len = dec_len;
cut = 0;
php_http_message_parser_state_push(parser, 2, PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL, PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
}
}
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL:
{
zval zcl;
ZVAL_LONG(&zcl, php_http_message_body_size((*message)->body));
zend_hash_str_update(&(*message)->hdrs, "Content-Length", lenof("Content-Length"), &zcl);
break;
}
case PHP_HTTP_MESSAGE_PARSER_STATE_DONE:
{
char *ptr = buffer->data;
while (ptr - buffer->data < buffer->used && PHP_HTTP_IS_CTYPE(space, *ptr)) {
++ptr;
}
php_http_buffer_cut(buffer, 0, ptr - buffer->data);
if (!(flags & PHP_HTTP_MESSAGE_PARSER_GREEDY)) {
return PHP_HTTP_MESSAGE_PARSER_STATE_DONE;
}
break;
}
}
}
return php_http_message_parser_state_is(parser);
}
static zend_class_entry *php_http_message_parser_class_entry;
zend_class_entry *php_http_get_message_parser_class_entry(void)
{
return php_http_message_parser_class_entry;
}
static zend_object_handlers php_http_message_parser_object_handlers;
zend_object *php_http_message_parser_object_new(zend_class_entry *ce)
{
return &php_http_message_parser_object_new_ex(ce, NULL)->zo;
}
php_http_message_parser_object_t *php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser)
{
php_http_message_parser_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
if (parser) {
o->parser = parser;
} else {
o->parser = php_http_message_parser_init(NULL);
}
php_http_buffer_init(&o->buffer);
o->zo.handlers = &php_http_message_parser_object_handlers;
return o;
}
void php_http_message_parser_object_free(zend_object *object)
{
php_http_message_parser_object_t *o = PHP_HTTP_OBJ(object, NULL);
if (o->parser) {
php_http_message_parser_free(&o->parser);
}
php_http_buffer_dtor(&o->buffer);
zend_object_std_dtor(object);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_getState, 0, 0, 0)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessageParser, getState)
{
php_http_message_parser_object_t *parser_obj = PHP_HTTP_OBJ(NULL, getThis());
zend_parse_parameters_none();
/* always return the real state */
RETVAL_LONG(php_http_message_parser_state_is(parser_obj->parser));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_parse, 0, 0, 3)
ZEND_ARG_INFO(0, data)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(1, message)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessageParser, parse)
{
php_http_message_parser_object_t *parser_obj;
zval *zmsg;
char *data_str;
size_t data_len;
zend_long flags;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "slz", &data_str, &data_len, &flags, &zmsg), invalid_arg, return);
parser_obj = PHP_HTTP_OBJ(NULL, getThis());
php_http_buffer_append(&parser_obj->buffer, data_str, data_len);
RETVAL_LONG(php_http_message_parser_parse(parser_obj->parser, &parser_obj->buffer, flags, &parser_obj->parser->message));
ZVAL_DEREF(zmsg);
zval_dtor(zmsg);
ZVAL_NULL(zmsg);
if (parser_obj->parser->message) {
php_http_message_t *msg_cpy = php_http_message_copy(parser_obj->parser->message, NULL);
php_http_message_object_t *msg_obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), msg_cpy);
ZVAL_OBJ(zmsg, &msg_obj->zo);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpMessageParser_stream, 0, 0, 3)
ZEND_ARG_INFO(0, stream)
ZEND_ARG_INFO(0, flags)
ZEND_ARG_INFO(1, message)
ZEND_END_ARG_INFO();
static PHP_METHOD(HttpMessageParser, stream)
{
php_http_message_parser_object_t *parser_obj;
zend_error_handling zeh;
zval *zmsg, *zstream;
php_stream *s;
zend_long flags;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "rlz", &zstream, &flags, &zmsg), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_unexpected_val_class_entry(), &zeh);
php_stream_from_zval(s, zstream);
zend_restore_error_handling(&zeh);
parser_obj = PHP_HTTP_OBJ(NULL, getThis());
RETVAL_LONG(php_http_message_parser_parse_stream(parser_obj->parser, &parser_obj->buffer, s, flags, &parser_obj->parser->message));
ZVAL_DEREF(zmsg);
zval_dtor(zmsg);
ZVAL_NULL(zmsg);
if (parser_obj->parser->message) {
php_http_message_t *msg_cpy = php_http_message_copy(parser_obj->parser->message, NULL);
php_http_message_object_t *msg_obj = php_http_message_object_new_ex(php_http_message_get_class_entry(), msg_cpy);
ZVAL_OBJ(zmsg, &msg_obj->zo);
}
}
static zend_function_entry php_http_message_parser_methods[] = {
PHP_ME(HttpMessageParser, getState, ai_HttpMessageParser_getState, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageParser, parse, ai_HttpMessageParser_parse, ZEND_ACC_PUBLIC)
PHP_ME(HttpMessageParser, stream, ai_HttpMessageParser_stream, ZEND_ACC_PUBLIC)
{NULL, NULL, NULL}
};
PHP_MINIT_FUNCTION(http_message_parser)
{
zend_class_entry ce;
INIT_NS_CLASS_ENTRY(ce, "http\\Message", "Parser", php_http_message_parser_methods);
php_http_message_parser_class_entry = zend_register_internal_class(&ce);
memcpy(&php_http_message_parser_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
php_http_message_parser_class_entry->create_object = php_http_message_parser_object_new;
php_http_message_parser_object_handlers.clone_obj = NULL;
php_http_message_parser_object_handlers.free_obj = php_http_message_parser_object_free;
php_http_message_parser_object_handlers.offset = XtOffsetOf(php_http_message_parser_object_t, zo);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("CLEANUP"), PHP_HTTP_MESSAGE_PARSER_CLEANUP);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("DUMB_BODIES"), PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("EMPTY_REDIRECTS"), PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("GREEDY"), PHP_HTTP_MESSAGE_PARSER_GREEDY);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_FAILURE"), PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_START"), PHP_HTTP_MESSAGE_PARSER_STATE_START);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_HEADER_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DUMB"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_LENGTH"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_CHUNKED"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_BODY_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_UPDATE_CL"), PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL);
zend_declare_class_constant_long(php_http_message_parser_class_entry, ZEND_STRL("STATE_DONE"), PHP_HTTP_MESSAGE_PARSER_STATE_DONE);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_message_parser.h 0000644 0001750 0000144 00000006755 12667772426 020247 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_MESSAGE_PARSER_H
#define PHP_HTTP_MESSAGE_PARSER_H
#include "php_http_header_parser.h"
#include "php_http_encoding.h"
#include "php_http_message.h"
typedef enum php_http_message_parser_state {
PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE = FAILURE,
PHP_HTTP_MESSAGE_PARSER_STATE_START = 0,
PHP_HTTP_MESSAGE_PARSER_STATE_HEADER,
PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE,
PHP_HTTP_MESSAGE_PARSER_STATE_BODY,
PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB,
PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH,
PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED,
PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE,
PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL,
PHP_HTTP_MESSAGE_PARSER_STATE_DONE
} php_http_message_parser_state_t;
#define PHP_HTTP_MESSAGE_PARSER_CLEANUP 0x1
#define PHP_HTTP_MESSAGE_PARSER_DUMB_BODIES 0x2
#define PHP_HTTP_MESSAGE_PARSER_EMPTY_REDIRECTS 0x4
#define PHP_HTTP_MESSAGE_PARSER_GREEDY 0x8
typedef struct php_http_message_parser {
php_http_header_parser_t header;
zend_ptr_stack stack;
size_t body_length;
php_http_message_t *message;
php_http_encoding_stream_t *dechunk;
php_http_encoding_stream_t *inflate;
} php_http_message_parser_t;
PHP_HTTP_API php_http_message_parser_t *php_http_message_parser_init(php_http_message_parser_t *parser);
PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_push(php_http_message_parser_t *parser, unsigned argc, ...);
PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_is(php_http_message_parser_t *parser);
PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_state_pop(php_http_message_parser_t *parser);
PHP_HTTP_API void php_http_message_parser_dtor(php_http_message_parser_t *parser);
PHP_HTTP_API void php_http_message_parser_free(php_http_message_parser_t **parser);
PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse(php_http_message_parser_t *parser, php_http_buffer_t *buffer, unsigned flags, php_http_message_t **message);
PHP_HTTP_API php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_http_buffer_t *buffer, php_stream *s, unsigned flags, php_http_message_t **message);
typedef struct php_http_message_parser_object {
php_http_buffer_t buffer;
php_http_message_parser_t *parser;
zend_object zo;
} php_http_message_parser_object_t;
PHP_HTTP_API zend_class_entry *php_http_get_message_parser_class_entry(void);
PHP_MINIT_FUNCTION(http_message_parser);
zend_object *php_http_message_parser_object_new(zend_class_entry *ce);
php_http_message_parser_object_t *php_http_message_parser_object_new_ex(zend_class_entry *ce, php_http_message_parser_t *parser);
void php_http_message_parser_object_free(zend_object *object);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_misc.c 0000644 0001750 0000144 00000014562 12667772426 016170 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
#include
/* SLEEP */
void php_http_sleep(double s)
{
#if defined(PHP_WIN32)
Sleep((DWORD) PHP_HTTP_MSEC(s));
#elif defined(HAVE_USLEEP)
usleep(PHP_HTTP_USEC(s));
#elif defined(HAVE_NANOSLEEP)
struct timespec req, rem;
req.tv_sec = (time_t) s;
req.tv_nsec = PHP_HTTP_NSEC(s) % PHP_HTTP_NANOSEC;
while (nanosleep(&req, &rem) && (errno == EINTR) && (PHP_HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > PHP_HTTP_NSEC(PHP_HTTP_DIFFSEC))) {
req.tv_sec = rem.tv_sec;
req.tv_nsec = rem.tv_nsec;
}
#else
struct timeval timeout;
timeout.tv_sec = (time_t) s;
timeout.tv_usec = PHP_HTTP_USEC(s) % PHP_HTTP_MCROSEC;
select(0, NULL, NULL, NULL, &timeout);
#endif
}
/* STRING UTILITIES */
int php_http_match(const char *haystack_str, const char *needle_str, int flags)
{
int result = 0;
if (!haystack_str || !needle_str) {
return result;
}
if (flags & PHP_HTTP_MATCH_FULL) {
if (flags & PHP_HTTP_MATCH_CASE) {
result = !strcmp(haystack_str, needle_str);
} else {
result = !strcasecmp(haystack_str, needle_str);
}
} else {
const char *found;
char *haystack = estrdup(haystack_str), *needle = estrdup(needle_str);
if (flags & PHP_HTTP_MATCH_CASE) {
found = zend_memnstr(haystack, needle, strlen(needle), haystack+strlen(haystack));
} else {
found = php_stristr(haystack, needle, strlen(haystack), strlen(needle));
}
if (found) {
if (!(flags & PHP_HTTP_MATCH_WORD)
|| ( (found == haystack || !PHP_HTTP_IS_CTYPE(alnum, *(found - 1)))
&& (!*(found + strlen(needle)) || !PHP_HTTP_IS_CTYPE(alnum, *(found + strlen(needle))))
)
) {
result = 1;
}
}
PTR_FREE(haystack);
PTR_FREE(needle);
}
return result;
}
char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
{
size_t i = 1;
int wasalpha;
if (key && key_len) {
if ((wasalpha = PHP_HTTP_IS_CTYPE(alpha, key[0]))) {
key[0] = (char) (uctitle ? PHP_HTTP_TO_CTYPE(upper, key[0]) : PHP_HTTP_TO_CTYPE(lower, key[0]));
}
PHP_HTTP_DUFF(key_len,
if (PHP_HTTP_IS_CTYPE(alpha, key[i])) {
key[i] = (char) (((!wasalpha) && uctitle) ? PHP_HTTP_TO_CTYPE(upper, key[i]) : PHP_HTTP_TO_CTYPE(lower, key[i]));
wasalpha = 1;
} else {
if (xhyphen && (key[i] == '_')) {
key[i] = '-';
}
wasalpha = 0;
}
++i;
);
}
return key;
}
size_t php_http_boundary(char *buf, size_t buf_len)
{
return snprintf(buf, buf_len, "%15.15F", sapi_get_request_time() * php_combined_lcg());
}
int php_http_select_str(const char *cmp, int argc, ...)
{
va_list argv;
int match = -1;
if (cmp && argc > 0) {
int i;
va_start(argv, argc);
for (i = 0; i < argc; ++i) {
const char *test = va_arg(argv, const char *);
if (!strcasecmp(cmp, test)) {
match = i;
break;
}
}
va_end(argv);
}
return match;
}
/* ARRAYS */
unsigned php_http_array_list(HashTable *ht, unsigned argc, ...)
{
unsigned argl = 0;
va_list argv;
zval *data;
va_start(argv, argc);
ZEND_HASH_FOREACH_VAL(ht, data) {
zval **argp = (zval **) va_arg(argv, zval **);
*argp = data;
++argl;
} ZEND_HASH_FOREACH_END();
va_end(argv);
return argl;
}
void php_http_array_copy_strings(zval *zp)
{
Z_TRY_ADDREF_P(zp);
convert_to_string_ex(zp);
}
int php_http_array_apply_append_func(zval *value, int num_args, va_list args, zend_hash_key *hash_key)
{
int flags;
char *key = NULL;
HashTable *dst;
zval *data = NULL;
dst = va_arg(args, HashTable *);
flags = va_arg(args, int);
if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->key) {
if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->key) {
key = php_http_pretty_key(estrndup(hash_key->key->val, hash_key->key->len), hash_key->key->len, 1, 1);
data = zend_hash_str_find(dst, key, hash_key->key->len);
} else if (hash_key->key) {
data = zend_hash_find(dst, hash_key->key);
} else {
data = zend_hash_index_find(dst, hash_key->h);
}
if (flags & ARRAY_JOIN_STRINGIFY) {
convert_to_string_ex(value);
}
Z_ADDREF_P(value);
if (data) {
if (Z_TYPE_P(data) != IS_ARRAY) {
convert_to_array(data);
}
add_next_index_zval(data, value);
} else if (key) {
zend_hash_str_update(dst, key, hash_key->key->len, value);
} else if (hash_key->key) {
zend_hash_update(dst, hash_key->key, value);
} else {
zend_hash_index_update(dst, hash_key->h, value);
}
if (key) {
efree(key);
}
}
return ZEND_HASH_APPLY_KEEP;
}
int php_http_array_apply_merge_func(zval *value, int num_args, va_list args, zend_hash_key *hash_key)
{
int flags;
char *key = NULL;
HashTable *dst;
dst = va_arg(args, HashTable *);
flags = va_arg(args, int);
if ((!(flags & ARRAY_JOIN_STRONLY)) || hash_key->key) {
if (flags & ARRAY_JOIN_STRINGIFY) {
convert_to_string_ex(value);
}
Z_TRY_ADDREF_P(value);
if ((flags & ARRAY_JOIN_PRETTIFY) && hash_key->key) {
key = php_http_pretty_key(estrndup(hash_key->key->val, hash_key->key->len), hash_key->key->len, 1, 1);
zend_hash_str_update(dst, key, hash_key->key->len, value);
efree(key);
} else if (hash_key->key) {
zend_hash_update(dst, hash_key->key, value);
} else {
zend_hash_index_update(dst, hash_key->h, value);
}
}
return ZEND_HASH_APPLY_KEEP;
}
/* PASS CALLBACK */
size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len)
{
php_http_pass_fcall_arg_t *fcd = cb_arg;
zval zdata;
ZVAL_STRINGL(&zdata, str, len);
if (SUCCESS == zend_fcall_info_argn(&fcd->fci, 2, &fcd->fcz, &zdata)) {
zend_fcall_info_call(&fcd->fci, &fcd->fcc, NULL, NULL);
zend_fcall_info_args_clear(&fcd->fci, 0);
}
zval_ptr_dtor(&zdata);
return len;
}
/* ZEND */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_misc.h 0000644 0001750 0000144 00000016536 12667772426 016200 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_MISC_H
#define PHP_HTTP_MISC_H
/* DEFAULTS */
/* DATE FORMAT RFC1123 */
#define PHP_HTTP_DATE_FORMAT "D, d M Y H:i:s \\G\\M\\T"
/* CR LF */
#define PHP_HTTP_CRLF "\r\n"
/* def URL arg separator */
#define PHP_HTTP_URL_ARGSEP "&"
/* send buffer size */
#define PHP_HTTP_SENDBUF_SIZE 40960
/* allowed characters of header field names */
#define PHP_HTTP_HEADER_NAME_CHARS "!#$%&'*+-.^_`|~1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
/* SLEEP */
#define PHP_HTTP_DIFFSEC (0.001)
#define PHP_HTTP_MLLISEC (1000)
#define PHP_HTTP_MCROSEC (1000 * 1000)
#define PHP_HTTP_NANOSEC (1000 * 1000 * 1000)
#define PHP_HTTP_MSEC(s) ((long)(s * PHP_HTTP_MLLISEC))
#define PHP_HTTP_USEC(s) ((long)(s * PHP_HTTP_MCROSEC))
#define PHP_HTTP_NSEC(s) ((long)(s * PHP_HTTP_NANOSEC))
PHP_HTTP_API void php_http_sleep(double s);
/* STRING UTILITIES */
#ifndef PTR_SET
# define PTR_SET(STR, SET) \
{ \
PTR_FREE(STR); \
STR = SET; \
}
#endif
#define STR_PTR(s) (s?s:"")
#define lenof(S) (sizeof(S) - 1)
#define PHP_HTTP_MATCH_LOOSE 0
#define PHP_HTTP_MATCH_CASE 0x01
#define PHP_HTTP_MATCH_WORD 0x10
#define PHP_HTTP_MATCH_FULL 0x20
#define PHP_HTTP_MATCH_STRICT (PHP_HTTP_MATCH_CASE|PHP_HTTP_MATCH_FULL)
int php_http_match(const char *haystack, const char *needle, int flags);
char *php_http_pretty_key(register char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen);
size_t php_http_boundary(char *buf, size_t len);
int php_http_select_str(const char *cmp, int argc, ...);
/* See "A Reusable Duff Device" By Ralf Holly, August 01, 2005 */
#define PHP_HTTP_DUFF_BREAK() times_=1
#define PHP_HTTP_DUFF(c, a) do { \
size_t count_ = (c); \
size_t times_ = (count_ + 7) >> 3; \
switch (count_ & 7){ \
case 0: do { \
a; \
case 7: \
a; \
case 6: \
a; \
case 5: \
a; \
case 4: \
a; \
case 3: \
a; \
case 2: \
a; \
case 1: \
a; \
} while (--times_ > 0); \
} \
} while (0)
static inline const char *php_http_locate_str(register const char *h, size_t h_len, const char *n, size_t n_len)
{
if (!n_len || !h_len || h_len < n_len) {
return NULL;
}
PHP_HTTP_DUFF(h_len - n_len + 1,
if (*h == *n && !strncmp(h + 1, n + 1, n_len - 1)) {
return h;
}
++h;
);
return NULL;
}
static inline const char *php_http_locate_eol(const char *line, int *eol_len)
{
const char *eol = strpbrk(line, "\r\n");
if (eol_len) {
*eol_len = eol ? ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1) : 0;
}
return eol;
}
static inline const char *php_http_locate_bin_eol(const char *bin, size_t len, int *eol_len)
{
register const char *eol = bin;
if (len > 0) {
PHP_HTTP_DUFF(len,
if (*eol == '\r' || *eol == '\n') {
if (eol_len) {
*eol_len = ((eol[0] == '\r' && eol[1] == '\n') ? 2 : 1);
}
return eol;
}
++eol;
);
}
return NULL;
}
/* ZEND */
#ifdef PHP_DEBUG
# undef HASH_OF
# define HASH_OF(p) ((HashTable*)(Z_TYPE_P(p)==IS_ARRAY ? Z_ARRVAL_P(p) : ((Z_TYPE_P(p)==IS_OBJECT ? Z_OBJ_HT_P(p)->get_properties((p)) : NULL))))
#endif
static inline void *PHP_HTTP_OBJ(zend_object *zo, zval *zv)
{
if (!zo) {
zo = Z_OBJ_P(zv);
}
return (char *) zo - zo->handlers->offset;
}
static inline zend_string *php_http_cs2zs(char *s, size_t l)
{
zend_string *str = erealloc(s, sizeof(*str) + l);
memmove(str->val, str, l);
str->val[l] = 0;
str->len = l;
str->h = 0;
GC_REFCOUNT(str) = 1;
GC_TYPE_INFO(str) = IS_STRING;
return str;
}
static inline ZEND_RESULT_CODE php_http_ini_entry(const char *name_str, size_t name_len, const char **val_str, size_t *val_len, zend_bool orig)
{
zend_ini_entry *ini_entry;
if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), name_str, name_len))) {
if (orig && ini_entry->modified) {
*val_str = ini_entry->orig_value->val;
*val_len = ini_entry->orig_value->len;
} else {
*val_str = ini_entry->value->val;
*val_len = ini_entry->value->len;
}
return SUCCESS;
}
return FAILURE;
}
#define Z_ISUSER(zv) (Z_TYPE(zv) <= 10)
#define Z_ISUSER_P(zvp) Z_ISUSER(*(zvp))
/* return object(values) */
#define ZVAL_OBJECT(z, o, addref) \
ZVAL_OBJ(z, o); \
if (addref) { \
Z_ADDREF_P(z); \
}
#define RETVAL_OBJECT(o, addref) \
ZVAL_OBJECT(return_value, o, addref)
#define RETURN_OBJECT(o, addref) \
RETVAL_OBJECT(o, addref); \
return
#define EMPTY_FUNCTION_ENTRY {NULL, NULL, NULL, 0, 0}
#define PHP_MINIT_CALL(func) PHP_MINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
#define PHP_RINIT_CALL(func) PHP_RINIT(func)(INIT_FUNC_ARGS_PASSTHRU)
#define PHP_MSHUTDOWN_CALL(func) PHP_MSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
#define PHP_RSHUTDOWN_CALL(func) PHP_RSHUTDOWN(func)(SHUTDOWN_FUNC_ARGS_PASSTHRU)
/* ARRAYS */
PHP_HTTP_API unsigned php_http_array_list(HashTable *ht, unsigned argc, ...);
typedef struct php_http_arrkey {
zend_ulong h;
zend_string *key;
unsigned allocated:1;
unsigned stringified:1;
} php_http_arrkey_t;
static inline void *php_http_arrkey_stringify(php_http_arrkey_t *arrkey, zend_hash_key *key)
{
if (arrkey) {
arrkey->allocated = 0;
} else {
arrkey = emalloc(sizeof(*arrkey));
arrkey->allocated = 1;
}
if (key) {
memcpy(arrkey, key, sizeof(*key));
}
if ((arrkey->stringified = !arrkey->key)) {
arrkey->key = zend_long_to_str(arrkey->h);
}
return arrkey;
}
static inline void php_http_arrkey_dtor(php_http_arrkey_t *arrkey)
{
if (arrkey->stringified) {
zend_string_release(arrkey->key);
}
if (arrkey->allocated) {
efree(arrkey);
}
}
#define array_copy(src, dst) zend_hash_copy(dst, src, (copy_ctor_func_t) zval_add_ref)
#define array_copy_strings(src, dst) zend_hash_copy(dst, src, php_http_array_copy_strings)
#define ARRAY_JOIN_STRONLY 0x01
#define ARRAY_JOIN_PRETTIFY 0x02
#define ARRAY_JOIN_STRINGIFY 0x04
#define array_join(src, dst, append, flags) zend_hash_apply_with_arguments(src, (append)?php_http_array_apply_append_func:php_http_array_apply_merge_func, 2, dst, (int)flags)
void php_http_array_copy_strings(zval *zp);
int php_http_array_apply_append_func(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key);
int php_http_array_apply_merge_func(zval *pDest, int num_args, va_list args, zend_hash_key *hash_key);
/* PASS CALLBACK */
typedef size_t (*php_http_pass_callback_t)(void *cb_arg, const char *str, size_t len);
typedef size_t (*php_http_pass_php_http_buffer_callback_t)(void *cb_arg, php_http_buffer_t *str);
typedef size_t (*php_http_pass_format_callback_t)(void *cb_arg, const char *fmt, ...);
typedef struct php_http_pass_fcall_arg {
zval fcz;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
} php_http_pass_fcall_arg_t;
PHP_HTTP_API size_t php_http_pass_fcall_callback(void *cb_arg, const char *str, size_t len);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_negotiate.c 0000644 0001750 0000144 00000012040 12667772426 017201 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static int php_http_negotiate_sort(const void *first, const void *second)
{
Bucket *b1 = (Bucket *) first, *b2 = (Bucket *) second;
int result = numeric_compare_function(&b1->val, &b2->val);
return (result > 0 ? -1 : (result < 0 ? 1 : 0));
}
#define M_PRI 5
#define M_SEC 2
#define M_ANY 1
#define M_NOT 0
#define M_ALL ~0
static inline unsigned php_http_negotiate_match(const char *param_str, size_t param_len, const char *supported_str, size_t supported_len, const char *sep_str, size_t sep_len)
{
unsigned match = M_NOT;
if (param_len == supported_len && !strncasecmp(param_str, supported_str, param_len)) {
/* that was easy */
match = M_ALL;
} else if (sep_str && sep_len) {
const char *param_sec = php_http_locate_str(param_str, param_len, sep_str, sep_len);
size_t param_pri_len = param_sec ? param_sec - param_str : param_len;
const char *supported_sec = php_http_locate_str(supported_str, supported_len, sep_str, sep_len);
size_t supported_pri_len = supported_sec ? supported_sec - supported_str : supported_len;
size_t cmp_len = MIN(param_pri_len, supported_pri_len);
if (((*param_str == '*') || (*supported_str == '*'))
|| ((param_pri_len == supported_pri_len) && !strncasecmp(param_str, supported_str, param_pri_len))
|| ((!param_sec || !supported_sec) && cmp_len && !strncasecmp(param_str, supported_str, cmp_len))
) {
match += M_PRI;
}
if (param_sec && supported_sec && !strcasecmp(param_sec, supported_sec)) {
match += M_SEC;
}
if ((param_sec && *(param_sec + sep_len) == '*')
|| (supported_sec && *(supported_sec + sep_len) == '*')
|| ((*param_str == '*') || (*supported_str == '*'))
) {
match += M_ANY;
}
}
#if 0
fprintf(stderr, "match: %s == %s => %u\n", supported_str, param_str, match);
#endif
return match;
}
static int php_http_negotiate_reduce(zval *p, int num_args, va_list args, zend_hash_key *hash_key)
{
unsigned best_match = 0;
php_http_arrkey_t key;
zval *value, *q = NULL;
zend_string *supported = zval_get_string(p);
HashTable *params = va_arg(args, HashTable *);
HashTable *result = va_arg(args, HashTable *);
const char *sep_str = va_arg(args, const char *);
size_t sep_len = va_arg(args, size_t);
ZEND_HASH_FOREACH_KEY_VAL(params, key.h, key.key, value)
{
unsigned match;
php_http_arrkey_stringify(&key, NULL);
match = php_http_negotiate_match(key.key->val, key.key->len, supported->val, supported->len, sep_str, sep_len);
if (match > best_match) {
best_match = match;
q = value;
}
php_http_arrkey_dtor(&key);
}
ZEND_HASH_FOREACH_END();
if (q && Z_DVAL_P(q) > 0) {
Z_TRY_ADDREF_P(q);
zend_hash_update(result, supported, q);
}
zend_string_release(supported);
return ZEND_HASH_APPLY_KEEP;
}
HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len)
{
HashTable *result = NULL;
if (value_str && value_len) {
unsigned i = 0;
zval arr, *val, *arg, *zq;
HashTable params;
php_http_arrkey_t key;
php_http_params_opts_t opts;
zend_hash_init(¶ms, 10, NULL, ZVAL_PTR_DTOR, 0);
php_http_params_opts_default_get(&opts);
opts.input.str = estrndup(value_str, value_len);
opts.input.len = value_len;
php_http_params_parse(¶ms, &opts);
efree(opts.input.str);
array_init(&arr);
ZEND_HASH_FOREACH_KEY_VAL(¶ms, key.h, key.key, val)
{
double q;
if ((arg = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("arguments")))
&& (IS_ARRAY == Z_TYPE_P(arg))
&& (zq = zend_hash_str_find(Z_ARRVAL_P(arg), ZEND_STRL("q")))) {
q = zval_get_double(zq);
} else {
q = 1.0 - ++i / 100.0;
}
#if 0
fprintf(stderr, "Q: %s=%1.3f\n", key.key->val, q);
#endif
if (key.key) {
add_assoc_double_ex(&arr, key.key->val, key.key->len, q);
} else {
add_index_double(&arr, key.h, q);
}
}
ZEND_HASH_FOREACH_END();
#if 0
zend_print_zval_r(&arr, 1);
#endif
ALLOC_HASHTABLE(result);
zend_hash_init(result, zend_hash_num_elements(supported), NULL, ZVAL_PTR_DTOR, 0);
zend_hash_apply_with_arguments(supported, php_http_negotiate_reduce, 4, Z_ARRVAL(arr), result, primary_sep_str, primary_sep_len);
zend_hash_destroy(¶ms);
zval_dtor(&arr);
zend_hash_sort(result, php_http_negotiate_sort, 0);
}
return result;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_negotiate.h 0000644 0001750 0000144 00000007606 12667772426 017222 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_NEGOTIATE_H
#define PHP_HTTP_NEGOTIATE_H
PHP_HTTP_API HashTable *php_http_negotiate(const char *value_str, size_t value_len, HashTable *supported, const char *primary_sep_str, size_t primary_sep_len);
static inline HashTable *php_http_negotiate_language(HashTable *supported, php_http_message_t *request)
{
HashTable *result = NULL;
size_t length;
char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Language"), &length, request);
if (value) {
result = php_http_negotiate(value, length, supported, "-", 1);
}
PTR_FREE(value);
return result;
}
static inline HashTable *php_http_negotiate_encoding(HashTable *supported, php_http_message_t *request)
{
HashTable *result = NULL;
size_t length;
char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Encoding"), &length, request);
if (value) {
result = php_http_negotiate(value, length, supported, NULL, 0);
}
PTR_FREE(value);
return result;
}
static inline HashTable *php_http_negotiate_charset(HashTable *supported, php_http_message_t *request)
{
HashTable *result = NULL;
size_t length;
char *value = php_http_env_get_request_header(ZEND_STRL("Accept-Charset"), &length, request);
if (value) {
result = php_http_negotiate(value, length, supported, NULL, 0);
}
PTR_FREE(value);
return result;
}
static inline HashTable *php_http_negotiate_content_type(HashTable *supported, php_http_message_t *request)
{
HashTable *result = NULL;
size_t length;
char *value = php_http_env_get_request_header(ZEND_STRL("Accept"), &length, request);
if (value) {
result = php_http_negotiate(value, length, supported, "/", 1);
}
PTR_FREE(value);
return result;
}
#define PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported) \
{ \
zval *value; \
\
zend_hash_internal_pointer_reset((supported)); \
if ((value = zend_hash_get_current_data((supported)))) { \
RETVAL_ZVAL(value, 1, 0); \
} else { \
RETVAL_NULL(); \
} \
}
#define PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array) \
PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
if (rs_array) { \
zval *value; \
\
ZEND_HASH_FOREACH_VAL(supported, value) \
{ \
zend_string *zs = zval_get_string(value); \
add_assoc_double_ex(rs_array, zs->val, zs->len, 1.0); \
zend_string_release(zs); \
} \
ZEND_HASH_FOREACH_END(); \
}
#define PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array) \
{ \
zend_string *key; \
zend_ulong idx; \
\
if (zend_hash_num_elements(result) && HASH_KEY_IS_STRING == zend_hash_get_current_key(result, &key, &idx)) { \
RETVAL_STR_COPY(key); \
} else { \
PHP_HTTP_DO_NEGOTIATE_DEFAULT(supported); \
} \
\
if (rs_array) { \
zend_hash_copy(Z_ARRVAL_P(rs_array), result, (copy_ctor_func_t) zval_add_ref); \
} \
\
zend_hash_destroy(result); \
FREE_HASHTABLE(result); \
}
#define PHP_HTTP_DO_NEGOTIATE(type, supported, rs_array) \
{ \
HashTable *result; \
if ((result = php_http_negotiate_ ##type(supported, NULL))) { \
PHP_HTTP_DO_NEGOTIATE_HANDLE_RESULT(result, supported, rs_array); \
} else { \
PHP_HTTP_DO_NEGOTIATE_HANDLE_DEFAULT(supported, rs_array); \
} \
}
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_object.c 0000644 0001750 0000144 00000007136 12667772426 016502 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static zend_object_handlers php_http_object_handlers;
zend_object *php_http_object_new(zend_class_entry *ce)
{
return &php_http_object_new_ex(ce, NULL)->zo;
}
php_http_object_t *php_http_object_new_ex(zend_class_entry *ce, void *intern)
{
php_http_object_t *o;
o = ecalloc(1, sizeof(*o) + zend_object_properties_size(ce));
zend_object_std_init(&o->zo, ce);
object_properties_init(&o->zo, ce);
o->intern = intern;
o->zo.handlers = &php_http_object_handlers;
return o;
}
void php_http_object_free(zend_object *object)
{
zend_object_std_dtor(object);
}
ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr)
{
void *obj;
if (!ce) {
ce = parent_ce;
} else if (parent_ce && !instanceof_function(ce, parent_ce)) {
php_http_throw(unexpected_val, "Class %s does not extend %s", ce->name->val, parent_ce->name->val);
return FAILURE;
}
obj = create(ce, intern_ptr);
if (obj_ptr) {
*obj_ptr = obj;
}
return SUCCESS;
}
php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len)
{
if (!cb) {
cb = ecalloc(1, sizeof(*cb));
} else {
memset(cb, 0, sizeof(*cb));
}
cb->fci.size = sizeof(cb->fci);
ZVAL_STRINGL(&cb->fci.function_name, method_str, method_len);
cb->fcc.initialized = 1;
cb->fcc.calling_scope = cb->fcc.called_scope = Z_OBJCE_P(zobject);
cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL);
return cb;
}
void php_http_object_method_dtor(php_http_object_method_t *cb)
{
zval_ptr_dtor(&cb->fci.function_name);
}
void php_http_object_method_free(php_http_object_method_t **cb)
{
if (*cb) {
php_http_object_method_dtor(*cb);
efree(*cb);
*cb = NULL;
}
}
ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval_ptr, int argc, zval *args)
{
ZEND_RESULT_CODE rv;
zval retval;
ZVAL_UNDEF(&retval);
Z_ADDREF_P(zobject);
cb->fci.object = Z_OBJ_P(zobject);
cb->fcc.object = Z_OBJ_P(zobject);
cb->fci.retval = retval_ptr ? retval_ptr : &retval;
cb->fci.param_count = argc;
cb->fci.params = args;
if (cb->fcc.called_scope != Z_OBJCE_P(zobject)) {
cb->fcc.called_scope = Z_OBJCE_P(zobject);
cb->fcc.function_handler = Z_OBJ_HT_P(zobject)->get_method(&Z_OBJ_P(zobject), Z_STR(cb->fci.function_name), NULL);
}
rv = zend_call_function(&cb->fci, &cb->fcc);
zval_ptr_dtor(zobject);
if (!retval_ptr && !Z_ISUNDEF(retval)) {
zval_ptr_dtor(&retval);
}
return rv;
}
PHP_MINIT_FUNCTION(http_object)
{
memcpy(&php_http_object_handlers, zend_get_std_object_handlers(), sizeof(php_http_object_handlers));
php_http_object_handlers.offset = XtOffsetOf(php_http_object_t, zo);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_object.h 0000644 0001750 0000144 00000003477 12667772426 016513 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_OBJECT_H
#define PHP_HTTP_OBJECT_H
typedef struct php_http_object {
void *intern;
zend_object zo;
} php_http_object_t;
zend_object *php_http_object_new(zend_class_entry *ce);
php_http_object_t *php_http_object_new_ex(zend_class_entry *ce, void *nothing);
typedef void *(*php_http_new_t)(zend_class_entry *ce, void *);
ZEND_RESULT_CODE php_http_new(void **obj_ptr, zend_class_entry *ce, php_http_new_t create, zend_class_entry *parent_ce, void *intern_ptr);
PHP_MINIT_FUNCTION(http_object);
typedef struct php_http_method {
zend_fcall_info fci;
zend_fcall_info_cache fcc;
} php_http_object_method_t;
php_http_object_method_t *php_http_object_method_init(php_http_object_method_t *cb, zval *zobject, const char *method_str, size_t method_len);
ZEND_RESULT_CODE php_http_object_method_call(php_http_object_method_t *cb, zval *zobject, zval *retval, int argc, zval *args);
void php_http_object_method_dtor(php_http_object_method_t *cb);
void php_http_object_method_free(php_http_object_method_t **cb);
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_options.c 0000644 0001750 0000144 00000006454 12667772426 016731 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static void php_http_options_hash_dtor(zval *pData)
{
php_http_option_t *opt = Z_PTR_P(pData);
zval_ptr_dtor(&opt->defval);
zend_hash_destroy(&opt->suboptions.options);
zend_string_release(opt->name);
pefree(opt, opt->persistent);
}
php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent)
{
if (!registry) {
registry = pecalloc(1, sizeof(*registry), persistent);
} else {
memset(registry, 0, sizeof(*registry));
}
registry->persistent = persistent;
zend_hash_init(®istry->options, 0, NULL, php_http_options_hash_dtor, persistent);
return registry;
}
ZEND_RESULT_CODE php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata)
{
zval *entry, *val;
php_http_option_t *opt;
ZEND_HASH_FOREACH_VAL(®istry->options, entry)
{
opt = Z_PTR_P(entry);
if (!(val = registry->getter(opt, options, userdata))) {
val = &opt->defval;
}
if (registry->setter) {
if (SUCCESS != registry->setter(opt, val, userdata)) {
return FAILURE;
}
} else if (!opt->setter || SUCCESS != opt->setter(opt, val, userdata)) {
return FAILURE;
}
}
ZEND_HASH_FOREACH_END();
return SUCCESS;
}
void php_http_options_dtor(php_http_options_t *registry)
{
zend_hash_destroy(®istry->options);
}
void php_http_options_free(php_http_options_t **registry)
{
if (*registry) {
php_http_options_dtor(*registry);
pefree(*registry, (*registry)->persistent);
*registry = NULL;
}
}
php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, ulong option, zend_uchar type)
{
php_http_option_t opt;
memset(&opt, 0, sizeof(opt));
php_http_options_init(&opt.suboptions, registry->persistent);
opt.suboptions.getter = registry->getter;
opt.suboptions.setter = registry->setter;
opt.persistent = registry->persistent;
opt.name = zend_string_init(name_str, name_len, registry->persistent);
opt.type = type;
opt.option = option;
switch ((opt.type = type)) {
case IS_TRUE:
ZVAL_TRUE(&opt.defval);
break;
case IS_FALSE:
ZVAL_FALSE(&opt.defval);
break;
case IS_LONG:
ZVAL_LONG(&opt.defval, 0);
break;
case IS_DOUBLE:
ZVAL_DOUBLE(&opt.defval, 0);
break;
default:
ZVAL_NULL(&opt.defval);
break;
}
return zend_hash_update_mem(®istry->options, opt.name, &opt, sizeof(opt));
}
zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata)
{
if (options) {
return zend_hash_find(options, opt->name);
}
return NULL;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_options.h 0000644 0001750 0000144 00000004264 12667772426 016733 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_OPTIONS_H
#define PHP_HTTP_OPTIONS_H
typedef struct php_http_option php_http_option_t;
typedef struct php_http_options php_http_options_t;
typedef ZEND_RESULT_CODE (*php_http_option_set_callback_t)(php_http_option_t *opt, zval *val, void *userdata);
typedef zval *(*php_http_option_get_callback_t)(php_http_option_t *opt, HashTable *options, void *userdata);
struct php_http_options {
HashTable options;
php_http_option_get_callback_t getter;
php_http_option_set_callback_t setter;
unsigned persistent:1;
};
struct php_http_option {
php_http_options_t suboptions;
zend_string *name;
ulong option;
zend_uchar type;
unsigned flags;
zval defval;
php_http_option_set_callback_t setter;
unsigned persistent:1;
};
PHP_HTTP_API php_http_options_t *php_http_options_init(php_http_options_t *registry, zend_bool persistent);
PHP_HTTP_API ZEND_RESULT_CODE php_http_options_apply(php_http_options_t *registry, HashTable *options, void *userdata);
PHP_HTTP_API void php_http_options_dtor(php_http_options_t *registry);
PHP_HTTP_API void php_http_options_free(php_http_options_t **registry);
PHP_HTTP_API php_http_option_t *php_http_option_register(php_http_options_t *registry, const char *name_str, size_t name_len, ulong option, zend_uchar type);
PHP_HTTP_API zval *php_http_option_get(php_http_option_t *opt, HashTable *options, void *userdata);
#endif /* PHP_HTTP_OPTIONS_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_params.c 0000644 0001750 0000144 00000111226 12667772426 016513 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
static php_http_params_token_t def_param_sep = {",", 1}, *def_param_sep_ptr[] = {&def_param_sep, NULL};
static php_http_params_token_t def_arg_sep = {";", 1}, *def_arg_sep_ptr[] = {&def_arg_sep, NULL};
static php_http_params_token_t def_val_sep = {"=", 1}, *def_val_sep_ptr[] = {&def_val_sep, NULL};
static php_http_params_opts_t def_opts = {
{NULL, 0},
def_param_sep_ptr,
def_arg_sep_ptr,
def_val_sep_ptr,
{{0}},
PHP_HTTP_PARAMS_DEFAULT
};
php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts)
{
if (!opts) {
opts = emalloc(sizeof(*opts));
}
memcpy(opts, &def_opts, sizeof(def_opts));
return opts;
}
typedef struct php_http_params_state {
php_http_params_token_t input;
php_http_params_token_t param;
php_http_params_token_t arg;
php_http_params_token_t val;
struct {
zval *param;
zval *args;
zval *val;
} current;
unsigned quotes:1;
unsigned escape:1;
unsigned rfc5987:1;
} php_http_params_state_t;
static inline void sanitize_escaped(zval *zv)
{
if (Z_STRVAL_P(zv)[0] == '"' && Z_STRVAL_P(zv)[Z_STRLEN_P(zv) - 1] == '"') {
size_t deq_len = Z_STRLEN_P(zv) - 2;
char *deq = estrndup(Z_STRVAL_P(zv) + 1, deq_len);
zval_dtor(zv);
ZVAL_STR(zv, php_http_cs2zs(deq, deq_len));
}
php_stripcslashes(Z_STR_P(zv));
}
static inline void quote_string(zend_string **zs, zend_bool force)
{
int len = (*zs)->len;
*zs = php_addcslashes(*zs, 1, ZEND_STRL("\0..\37\173\\\""));
if (force || len != (*zs)->len || strpbrk((*zs)->val, "()<>@,;:\"[]?={} ")) {
int len = (*zs)->len + 2;
*zs = zend_string_extend(*zs, len, 0);
memmove(&(*zs)->val[1], (*zs)->val, (*zs)->len);
(*zs)->val[0] = '"';
(*zs)->val[len-1] = '"';
(*zs)->val[len] = '\0';
zend_string_forget_hash_val(*zs);
}
}
/* if (Z_TYPE_P(zv) == IS_STRING) {
size_t len = Z_STRLEN_P(zv);
zend_string *stripped = php_addcslashes(Z_STR_P(zv), 0,
ZEND_STRL("\0..\37\173\\\""));
if (len != stripped->len || strpbrk(stripped->val, "()<>@,;:\"[]?={} ")) {
size_t len = stripped->len + 2;
char *str = emalloc(len + 1);
str[0] = '"';
memcpy(&str[1], stripped->val, stripped->len);
str[len-1] = '"';
str[len] = '\0';
zval_dtor(zv);
zend_string_release(stripped);
ZVAL_STR(zv, php_http_cs2zs(str, len));
} else {
zval_dtor(zv);
ZVAL_STR(zv, stripped);
}
*/
static inline void prepare_escaped(zval *zv)
{
if (Z_TYPE_P(zv) == IS_STRING) {
quote_string(&Z_STR_P(zv), 0);
} else {
zval_dtor(zv);
ZVAL_EMPTY_STRING(zv);
}
}
static inline void sanitize_urlencoded(zval *zv)
{
Z_STRLEN_P(zv) = php_raw_url_decode(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
}
static inline void prepare_urlencoded(zval *zv)
{
zend_string *str = php_raw_url_encode(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
zval_dtor(zv);
ZVAL_STR(zv, str);
}
static void sanitize_dimension(zval *zv)
{
zval arr, tmp, *cur = NULL;
char *var = NULL, *ptr = Z_STRVAL_P(zv), *end = Z_STRVAL_P(zv) + Z_STRLEN_P(zv);
long level = 0;
array_init(&arr);
cur = &arr;
while (ptr < end) {
if (!var) {
var = ptr;
}
switch (*ptr) {
case '[':
if (++level > PG(max_input_nesting_level)) {
zval_ptr_dtor(&arr);
php_error_docref(NULL, E_WARNING, "Max input nesting level of %ld exceeded", (long) PG(max_input_nesting_level));
return;
}
if (ptr - var == 0) {
++var;
break;
}
/* no break */
case ']':
ZVAL_NULL(&tmp);
convert_to_array(cur);
if (ptr - var) {
char chr = *ptr;
*ptr = '\0';
cur = zend_symtable_str_update(Z_ARRVAL_P(cur), var, ptr - var, &tmp);
*ptr = chr;
} else {
cur = zend_hash_next_index_insert(Z_ARRVAL_P(cur), &tmp);
}
var = NULL;
break;
}
++ptr;
}
if (zend_hash_num_elements(Z_ARRVAL(arr))) {
zval_dtor(zv);
ZVAL_COPY_VALUE(zv, &arr);
} else {
zval_ptr_dtor(&arr);
}
}
static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags);
static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags);
static void prepare_dimension(php_http_buffer_t *buf, php_http_buffer_t *keybuf, zval *zvalue, const char *pss, size_t psl, const char *vss, size_t vsl, unsigned flags)
{
HashTable *ht = HASH_OF(zvalue);
php_http_arrkey_t key;
zval *val;
php_http_buffer_t prefix;
if (!ZEND_HASH_GET_APPLY_COUNT(ht)) {
ZEND_HASH_INC_APPLY_COUNT(ht);
php_http_buffer_init(&prefix);
php_http_buffer_append(&prefix, keybuf->data, keybuf->used);
ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, val)
{
if (key.key && !*key.key->val) {
/* only public properties */
continue;
}
php_http_buffer_appends(&prefix, "[");
if (key.key) {
php_http_buffer_append(&prefix, key.key->val, key.key->len);
} else {
php_http_buffer_appendf(&prefix, "%lu", key.h);
}
php_http_buffer_appends(&prefix, "]");
if (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT) {
prepare_dimension(buf, &prefix, val, pss, psl, vss, vsl, flags);
} else {
zend_string *cpy = zval_get_string(val);
zval tmp;
ZVAL_STR(&tmp, cpy);
shift_key(buf, prefix.data, prefix.used, pss, psl, flags);
shift_val(buf, &tmp, vss, vsl, flags);
zend_string_release(cpy);
}
php_http_buffer_cut(&prefix, keybuf->used, prefix.used - keybuf->used);
}
ZEND_HASH_FOREACH_END();
ZEND_HASH_DEC_APPLY_COUNT(ht);
php_http_buffer_dtor(&prefix);
}
}
static inline void sanitize_key(unsigned flags, const char *str, size_t len, zval *zv, zend_bool *rfc5987)
{
char *eos;
zend_string *zs = zend_string_init(str, len, 0);
zval_dtor(zv);
ZVAL_STR(zv, php_trim(zs, NULL, 0, 3));
zend_string_release(zs);
if (flags & PHP_HTTP_PARAMS_ESCAPED) {
sanitize_escaped(zv);
}
if (!Z_STRLEN_P(zv)) {
return;
}
eos = &Z_STRVAL_P(zv)[Z_STRLEN_P(zv)-1];
if (*eos == '*') {
*eos = '\0';
*rfc5987 = 1;
Z_STRLEN_P(zv) -= 1;
}
if (flags & PHP_HTTP_PARAMS_URLENCODED) {
sanitize_urlencoded(zv);
}
if (flags & PHP_HTTP_PARAMS_DIMENSION) {
sanitize_dimension(zv);
}
}
static inline void sanitize_rfc5987(zval *zv, char **language, zend_bool *latin1)
{
char *ptr;
/* examples:
* iso-8850-1'de'bl%f6der%20schei%df%21
* utf-8'de-DE'bl%c3%b6der%20schei%c3%9f%21
*/
switch (Z_STRVAL_P(zv)[0]) {
case 'I':
case 'i':
if (!strncasecmp(Z_STRVAL_P(zv), "iso-8859-1", lenof("iso-8859-1"))) {
*latin1 = 1;
ptr = Z_STRVAL_P(zv) + lenof("iso-8859-1");
break;
}
/* no break */
case 'U':
case 'u':
if (!strncasecmp(Z_STRVAL_P(zv), "utf-8", lenof("utf-8"))) {
*latin1 = 0;
ptr = Z_STRVAL_P(zv) + lenof("utf-8");
break;
}
/* no break */
default:
return;
}
/* extract language */
if (*ptr == '\'') {
for (*language = ++ptr; *ptr && *ptr != '\''; ++ptr);
if (!*ptr) {
*language = NULL;
return;
}
*language = estrndup(*language, ptr - *language);
/* remainder */
ptr = estrdup(++ptr);
zval_dtor(zv);
ZVAL_STR(zv, php_http_cs2zs(ptr, strlen(ptr)));
}
}
static inline void sanitize_rfc5988(char *str, size_t len, zval *zv)
{
zend_string *zs = zend_string_init(str, len, 0);
zval_dtor(zv);
ZVAL_STR(zv, php_trim(zs, " ><", 3, 3));
zend_string_release(zs);
}
static inline void prepare_rfc5988(zval *zv)
{
if (Z_TYPE_P(zv) != IS_STRING) {
zval_dtor(zv);
ZVAL_EMPTY_STRING(zv);
}
}
static void utf8encode(zval *zv)
{
size_t pos, len = 0;
unsigned char *ptr = (unsigned char *) Z_STRVAL_P(zv);
while (*ptr) {
if (*ptr++ >= 0x80) {
++len;
}
++len;
}
ptr = safe_emalloc(1, len, 1);
for (len = 0, pos = 0; len <= Z_STRLEN_P(zv); ++len, ++pos) {
ptr[pos] = Z_STRVAL_P(zv)[len];
if ((ptr[pos]) >= 0x80) {
ptr[pos + 1] = 0x80 | (ptr[pos] & 0x3f);
ptr[pos] = 0xc0 | ((ptr[pos] >> 6) & 0x1f);
++pos;
}
}
zval_dtor(zv);
ZVAL_STR(zv, php_http_cs2zs((char *) ptr, pos-1));
}
static inline void sanitize_value(unsigned flags, const char *str, size_t len, zval *zv, zend_bool rfc5987)
{
char *language = NULL;
zend_bool latin1 = 0;
zend_string *zs = zend_string_init(str, len, 0);
zval_dtor(zv);
ZVAL_STR(zv, php_trim(zs, NULL, 0, 3));
zend_string_release(zs);
if (rfc5987) {
sanitize_rfc5987(zv, &language, &latin1);
}
if (flags & PHP_HTTP_PARAMS_ESCAPED) {
sanitize_escaped(zv);
}
if ((flags & PHP_HTTP_PARAMS_URLENCODED) || (rfc5987 && language)) {
sanitize_urlencoded(zv);
}
if (rfc5987 && language) {
zval tmp;
if (latin1) {
utf8encode(zv);
}
ZVAL_COPY_VALUE(&tmp, zv);
array_init(zv);
add_assoc_zval(zv, language, &tmp);
efree(language);
}
}
static inline void prepare_key(unsigned flags, char *old_key, size_t old_len, char **new_key, size_t *new_len)
{
zval zv;
ZVAL_STRINGL(&zv, old_key, old_len);
if (flags & PHP_HTTP_PARAMS_URLENCODED) {
prepare_urlencoded(&zv);
}
if (flags & PHP_HTTP_PARAMS_ESCAPED) {
if (flags & PHP_HTTP_PARAMS_RFC5988) {
prepare_rfc5988(&zv);
} else {
prepare_escaped(&zv);
}
}
*new_key = estrndup(Z_STRVAL(zv), Z_STRLEN(zv));
*new_len = Z_STRLEN(zv);
zval_ptr_dtor(&zv);
}
static inline void prepare_value(unsigned flags, zval *zv)
{
if (flags & PHP_HTTP_PARAMS_URLENCODED) {
prepare_urlencoded(zv);
}
if (flags & PHP_HTTP_PARAMS_ESCAPED) {
prepare_escaped(zv);
}
}
static void merge_param(HashTable *params, zval *zdata, zval **current_param, zval **current_args)
{
zval *ptr, *zdata_ptr;
php_http_arrkey_t hkey = {0};
#if 0
{
zval tmp;
INIT_PZVAL_ARRAY(&tmp, params);
fprintf(stderr, "params = ");
zend_print_zval_r(&tmp, 1);
fprintf(stderr, "\n");
}
#endif
zend_hash_get_current_key(Z_ARRVAL_P(zdata), &hkey.key, &hkey.h);
if ((hkey.key && !zend_hash_exists(params, hkey.key))
|| (!hkey.key && !zend_hash_index_exists(params, hkey.h))
) {
zval tmp, arg, *args;
/* create the entry if it doesn't exist */
ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata));
Z_TRY_ADDREF_P(ptr);
array_init(&tmp);
add_assoc_zval_ex(&tmp, ZEND_STRL("value"), ptr);
array_init(&arg);
args = zend_hash_str_update(Z_ARRVAL(tmp), "arguments", lenof("arguments"), &arg);
*current_args = args;
if (hkey.key) {
ptr = zend_hash_update(params, hkey.key, &tmp);
} else {
ptr = zend_hash_index_update(params, hkey.h, &tmp);
}
} else {
/* merge */
if (hkey.key) {
ptr = zend_hash_find(params, hkey.key);
} else {
ptr = zend_hash_index_find(params, hkey.h);
}
zdata_ptr = zdata;
if (Z_TYPE_P(ptr) == IS_ARRAY
&& (ptr = zend_hash_str_find(Z_ARRVAL_P(ptr), "value", lenof("value")))
&& (zdata_ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata_ptr)))
) {
/*
* params = [arr => [value => [0 => 1]]]
* ^- ptr
* zdata = [arr => [0 => NULL]]
* ^- zdata_ptr
*/
zval *test_ptr;
while (Z_TYPE_P(zdata_ptr) == IS_ARRAY && (test_ptr = zend_hash_get_current_data(Z_ARRVAL_P(zdata_ptr)))) {
if (Z_TYPE_P(test_ptr) == IS_ARRAY) {
zval *tmp_ptr = ptr;
/* now find key in ptr */
if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(zdata_ptr), &hkey.key, &hkey.h)) {
if ((ptr = zend_hash_find(Z_ARRVAL_P(ptr), hkey.key))) {
zdata_ptr = test_ptr;
} else {
ptr = tmp_ptr;
Z_TRY_ADDREF_P(test_ptr);
ptr = zend_hash_update(Z_ARRVAL_P(ptr), hkey.key, test_ptr);
break;
}
} else {
if ((ptr = zend_hash_index_find(Z_ARRVAL_P(ptr), hkey.h))) {
zdata_ptr = test_ptr;
} else if (hkey.h) {
ptr = tmp_ptr;
Z_TRY_ADDREF_P(test_ptr);
ptr = zend_hash_index_update(Z_ARRVAL_P(ptr), hkey.h, test_ptr);
break;
} else {
ptr = tmp_ptr;
Z_TRY_ADDREF_P(test_ptr);
ptr = zend_hash_next_index_insert(Z_ARRVAL_P(ptr), test_ptr);
break;
}
}
} else {
/* this is the leaf */
Z_TRY_ADDREF_P(test_ptr);
if (Z_TYPE_P(ptr) != IS_ARRAY) {
zval_dtor(ptr);
array_init(ptr);
}
if (HASH_KEY_IS_STRING == zend_hash_get_current_key(Z_ARRVAL_P(zdata_ptr), &hkey.key, &hkey.h)) {
ptr = zend_hash_update(Z_ARRVAL_P(ptr), hkey.key, test_ptr);
} else if (hkey.h) {
ptr = zend_hash_index_update(Z_ARRVAL_P(ptr), hkey.h, test_ptr);
} else {
ptr = zend_hash_next_index_insert(Z_ARRVAL_P(ptr), test_ptr);
}
break;
}
}
}
}
/* bubble up */
while (Z_TYPE_P(ptr) == IS_ARRAY) {
zval *tmp = zend_hash_get_current_data(Z_ARRVAL_P(ptr));
if (tmp) {
ptr = tmp;
} else {
break;
}
}
*current_param = ptr;
}
static void push_param(HashTable *params, php_http_params_state_t *state, const php_http_params_opts_t *opts)
{
if (state->val.str) {
if (0 < (state->val.len = state->input.str - state->val.str)) {
sanitize_value(opts->flags, state->val.str, state->val.len, state->current.val, state->rfc5987);
}
state->rfc5987 = 0;
} else if (state->arg.str) {
if (0 < (state->arg.len = state->input.str - state->arg.str)) {
zval val, key;
zend_bool rfc5987 = 0;
ZVAL_NULL(&key);
sanitize_key(opts->flags, state->arg.str, state->arg.len, &key, &rfc5987);
state->rfc5987 = rfc5987;
if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) {
ZVAL_TRUE(&val);
if (rfc5987) {
zval *rfc;
if ((rfc = zend_hash_str_find(Z_ARRVAL_P(state->current.args), ZEND_STRL("*rfc5987*")))) {
state->current.val = zend_symtable_str_update(Z_ARRVAL_P(rfc), Z_STRVAL(key), Z_STRLEN(key), &val);
} else {
zval tmp;
array_init_size(&tmp, 1);
state->current.val = zend_symtable_str_update(Z_ARRVAL(tmp), Z_STRVAL(key), Z_STRLEN(key), &val);
zend_symtable_str_update(Z_ARRVAL_P(state->current.args), ZEND_STRL("*rfc5987*"), &tmp);
}
} else {
state->current.val = zend_symtable_str_update(Z_ARRVAL_P(state->current.args), Z_STRVAL(key), Z_STRLEN(key), &val);
}
}
zval_dtor(&key);
}
} else if (state->param.str) {
if (0 < (state->param.len = state->input.str - state->param.str)) {
zval prm, arg, val, key;
zend_bool rfc5987 = 0;
ZVAL_NULL(&key);
if (opts->flags & PHP_HTTP_PARAMS_RFC5988) {
sanitize_rfc5988(state->param.str, state->param.len, &key);
} else {
sanitize_key(opts->flags, state->param.str, state->param.len, &key, &rfc5987);
state->rfc5987 = rfc5987;
}
if (Z_TYPE(key) == IS_ARRAY) {
merge_param(params, &key, &state->current.val, &state->current.args);
} else if (Z_TYPE(key) == IS_STRING && Z_STRLEN(key)) {
// FIXME: array_init_size(&prm, 2);
array_init(&prm);
if (!Z_ISUNDEF(opts->defval)) {
ZVAL_COPY_VALUE(&val, &opts->defval);
zval_copy_ctor(&val);
} else {
ZVAL_TRUE(&val);
}
if (rfc5987 && (opts->flags & PHP_HTTP_PARAMS_RFC5987)) {
state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "*rfc5987*", lenof("*rfc5987*"), &val);
} else {
state->current.val = zend_hash_str_update(Z_ARRVAL(prm), "value", lenof("value"), &val);
}
// FIXME: array_init_size(&arg, 3);
array_init(&arg);
state->current.args = zend_hash_str_update(Z_ARRVAL(prm), "arguments", lenof("arguments"), &arg);
state->current.param = zend_symtable_str_update(params, Z_STRVAL(key), Z_STRLEN(key), &prm);
}
zval_ptr_dtor(&key);
}
}
}
static inline zend_bool check_str(const char *chk_str, size_t chk_len, const char *sep_str, size_t sep_len) {
return 0 < sep_len && chk_len >= sep_len && *chk_str == *sep_str && !memcmp(chk_str + 1, sep_str + 1, sep_len - 1);
}
static size_t check_sep(php_http_params_state_t *state, php_http_params_token_t **separators)
{
php_http_params_token_t **sep = separators;
if (state->quotes || state->escape) {
return 0;
}
if (sep) while (*sep) {
if (check_str(state->input.str, state->input.len, (*sep)->str, (*sep)->len)) {
return (*sep)->len;
}
++sep;
}
return 0;
}
static void skip_sep(size_t skip, php_http_params_state_t *state, php_http_params_token_t **param, php_http_params_token_t **arg, php_http_params_token_t **val)
{
size_t sep_len;
state->input.str += skip;
state->input.len -= skip;
while ( (param && (sep_len = check_sep(state, param)))
|| (arg && (sep_len = check_sep(state, arg)))
|| (val && (sep_len = check_sep(state, val)))
) {
state->input.str += sep_len;
state->input.len -= sep_len;
}
}
HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts)
{
php_http_params_state_t state = {{NULL,0}, {NULL,0}, {NULL,0}, {NULL,0}, {NULL,NULL,NULL}, 0, 0};
state.input.str = opts->input.str;
state.input.len = opts->input.len;
if (!params) {
ALLOC_HASHTABLE(params);
ZEND_INIT_SYMTABLE(params);
}
while (state.input.len) {
if ((opts->flags & PHP_HTTP_PARAMS_RFC5988) && !state.arg.str) {
if (*state.input.str == '<') {
state.quotes = 1;
} else if (*state.input.str == '>') {
state.quotes = 0;
}
} else if (*state.input.str == '"' && !state.escape) {
state.quotes = !state.quotes;
} else {
state.escape = (*state.input.str == '\\');
}
if (!state.param.str) {
/* initialize */
skip_sep(0, &state, opts->param, opts->arg, opts->val);
state.param.str = state.input.str;
} else {
size_t sep_len;
/* are we at a param separator? */
if (0 < (sep_len = check_sep(&state, opts->param))) {
push_param(params, &state, opts);
skip_sep(sep_len, &state, opts->param, opts->arg, opts->val);
/* start off with a new param */
state.param.str = state.input.str;
state.param.len = 0;
state.arg.str = NULL;
state.arg.len = 0;
state.val.str = NULL;
state.val.len = 0;
continue;
} else
/* are we at an arg separator? */
if (0 < (sep_len = check_sep(&state, opts->arg))) {
push_param(params, &state, opts);
skip_sep(sep_len, &state, NULL, opts->arg, opts->val);
/* continue with a new arg */
state.arg.str = state.input.str;
state.arg.len = 0;
state.val.str = NULL;
state.val.len = 0;
continue;
} else
/* are we at a val separator? */
if (0 < (sep_len = check_sep(&state, opts->val))) {
/* only handle separator if we're not already reading in a val */
if (!state.val.str) {
push_param(params, &state, opts);
skip_sep(sep_len, &state, NULL, NULL, opts->val);
state.val.str = state.input.str;
state.val.len = 0;
continue;
}
}
}
if (state.input.len) {
++state.input.str;
--state.input.len;
}
}
/* finalize */
push_param(params, &state, opts);
return params;
}
static inline void shift_key(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags)
{
char *str;
size_t len;
if (buf->used) {
php_http_buffer_append(buf, ass, asl);
}
prepare_key(flags, key_str, key_len, &str, &len);
php_http_buffer_append(buf, str, len);
efree(str);
}
static inline void shift_rfc5987(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags)
{
HashTable *ht = HASH_OF(zvalue);
zval *zdata, tmp;
zend_string *zs;
php_http_arrkey_t key = {0};
if ((zdata = zend_hash_get_current_data(ht))
&& HASH_KEY_NON_EXISTENT != zend_hash_get_current_key(ht, &key.key, &key.h)
) {
php_http_arrkey_stringify(&key, NULL);
php_http_buffer_appendf(buf, "*%.*sutf-8'%.*s'",
(int) (vsl > INT_MAX ? INT_MAX : vsl), vss,
(int) (key.key->len > INT_MAX ? INT_MAX : key.key->len), key.key->val);
php_http_arrkey_dtor(&key);
if (Z_TYPE_P(zdata) == IS_INDIRECT) {
zdata = Z_INDIRECT_P(zdata);
}
zs = zval_get_string(zdata);
ZVAL_STR(&tmp, zs);
prepare_value(flags | PHP_HTTP_PARAMS_URLENCODED, &tmp);
php_http_buffer_append(buf, Z_STRVAL(tmp), Z_STRLEN(tmp));
zval_ptr_dtor(&tmp);
}
}
static inline void shift_rfc5988(php_http_buffer_t *buf, char *key_str, size_t key_len, const char *ass, size_t asl, unsigned flags)
{
char *str;
size_t len;
if (buf->used) {
php_http_buffer_append(buf, ass, asl);
}
prepare_key(flags, key_str, key_len, &str, &len);
php_http_buffer_appends(buf, "<");
php_http_buffer_append(buf, str, len);
php_http_buffer_appends(buf, ">");
efree(str);
}
static inline void shift_rfc5988_val(php_http_buffer_t *buf, zval *zv, const char *vss, size_t vsl, unsigned flags)
{
zend_string *zs = zval_get_string(zv);
quote_string(&zs, 1);
php_http_buffer_append(buf, vss, vsl);
php_http_buffer_append(buf, zs->val, zs->len);
zend_string_release(zs);
}
static inline void shift_val(php_http_buffer_t *buf, zval *zvalue, const char *vss, size_t vsl, unsigned flags)
{
zval tmp;
zend_string *zs;
switch (Z_TYPE_P(zvalue)) {
case IS_TRUE:
break;
case IS_FALSE:
php_http_buffer_append(buf, vss, vsl);
php_http_buffer_appends(buf, "0");
break;
default:
zs = zval_get_string(zvalue);
ZVAL_STR(&tmp, zs);
prepare_value(flags, &tmp);
php_http_buffer_append(buf, vss, vsl);
php_http_buffer_append(buf, Z_STRVAL(tmp), Z_STRLEN(tmp));
zval_ptr_dtor(&tmp);
break;
}
}
static void shift_arg(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags)
{
if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
php_http_arrkey_t key;
HashTable *ht = HASH_OF(zvalue);
zval *val;
zend_bool rfc5987 = !strcmp(key_str, "*rfc5987*");
if (!rfc5987) {
shift_key(buf, key_str, key_len, ass, asl, flags);
}
ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, val)
{
/* did you mean recursion? */
php_http_arrkey_stringify(&key, NULL);
if (rfc5987 && (Z_TYPE_P(val) == IS_ARRAY || Z_TYPE_P(val) == IS_OBJECT)) {
shift_key(buf, key.key->val, key.key->len, ass, asl, flags);
shift_rfc5987(buf, val, vss, vsl, flags);
} else {
shift_arg(buf, key.key->val, key.key->len, val, ass, asl, vss, vsl, flags);
}
php_http_arrkey_dtor(&key);
}
ZEND_HASH_FOREACH_END();
} else {
shift_key(buf, key_str, key_len, ass, asl, flags);
if (flags & PHP_HTTP_PARAMS_RFC5988) {
switch (key_len) {
case lenof("rel"):
case lenof("title"):
case lenof("anchor"):
/* some args must be quoted */
if (0 <= php_http_select_str(key_str, 3, "rel", "title", "anchor")) {
shift_rfc5988_val(buf, zvalue, vss, vsl, flags);
return;
}
break;
}
}
shift_val(buf, zvalue, vss, vsl, flags);
}
}
static void shift_param(php_http_buffer_t *buf, char *key_str, size_t key_len, zval *zvalue, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags, zend_bool rfc5987)
{
if (Z_TYPE_P(zvalue) == IS_ARRAY || Z_TYPE_P(zvalue) == IS_OBJECT) {
/* treat as arguments, unless we care for dimensions or rfc5987 */
if (flags & PHP_HTTP_PARAMS_DIMENSION) {
php_http_buffer_t *keybuf = php_http_buffer_from_string(key_str, key_len);
prepare_dimension(buf, keybuf, zvalue, pss, psl, vss, vsl, flags);
php_http_buffer_free(&keybuf);
} else if (rfc5987) {
shift_key(buf, key_str, key_len, pss, psl, flags);
shift_rfc5987(buf, zvalue, vss, vsl, flags);
} else {
shift_arg(buf, key_str, key_len, zvalue, ass, asl, vss, vsl, flags);
}
} else {
if (flags & PHP_HTTP_PARAMS_RFC5988) {
shift_rfc5988(buf, key_str, key_len, pss, psl, flags);
} else {
shift_key(buf, key_str, key_len, pss, psl, flags);
}
shift_val(buf, zvalue, vss, vsl, flags);
}
}
php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags)
{
zval *zparam;
php_http_arrkey_t key;
zend_bool rfc5987 = 0;
if (!buf) {
buf = php_http_buffer_init(NULL);
}
ZEND_HASH_FOREACH_KEY_VAL(params, key.h, key.key, zparam)
{
zval *zvalue, *zargs;
if (Z_TYPE_P(zparam) != IS_ARRAY) {
zvalue = zparam;
} else {
if (!(zvalue = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("value")))) {
if (!(zvalue = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("*rfc5987*")))) {
zvalue = zparam;
} else {
rfc5987 = 1;
}
}
}
php_http_arrkey_stringify(&key, NULL);
shift_param(buf, key.key->val, key.key->len, zvalue, pss, psl, ass, asl, vss, vsl, flags, rfc5987);
php_http_arrkey_dtor(&key);
if (Z_TYPE_P(zparam) == IS_ARRAY) {
zval *tmp = zend_hash_str_find(Z_ARRVAL_P(zparam), ZEND_STRL("arguments"));
if (tmp) {
zvalue = tmp;
} else if (zvalue == zparam) {
continue;
} else {
zvalue = zparam;
}
}
if (Z_TYPE_P(zvalue) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zvalue), key.h, key.key, zargs)
{
if (zvalue == zparam && key.key && zend_string_equals_literal(key.key, "value")) {
continue;
}
php_http_arrkey_stringify(&key, NULL);
shift_arg(buf, key.key->val, key.key->len, zargs, ass, asl, vss, vsl, flags);
php_http_arrkey_dtor(&key);
}
ZEND_HASH_FOREACH_END();
}
}
ZEND_HASH_FOREACH_END();
php_http_buffer_shrink(buf);
php_http_buffer_fix(buf);
return buf;
}
php_http_params_token_t **php_http_params_separator_init(zval *zv)
{
zval *sep, ztmp;
php_http_params_token_t **ret, **tmp;
if (!zv) {
return NULL;
}
ZVAL_DUP(&ztmp, zv);
zv = &ztmp;
convert_to_array(zv);
ret = ecalloc(zend_hash_num_elements(Z_ARRVAL_P(zv)) + 1, sizeof(*ret));
tmp = ret;
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(zv), sep)
{
zend_string *zs = zval_get_string(sep);
if (zs->len) {
*tmp = emalloc(sizeof(**tmp));
(*tmp)->str = estrndup(zs->val, (*tmp)->len = zs->len);
++tmp;
}
zend_string_release(zs);
}
ZEND_HASH_FOREACH_END();
zval_ptr_dtor(&ztmp);
*tmp = NULL;
return ret;
}
void php_http_params_separator_free(php_http_params_token_t **separator)
{
php_http_params_token_t **sep = separator;
if (sep) {
while (*sep) {
PTR_FREE((*sep)->str);
efree(*sep);
++sep;
}
efree(separator);
}
}
static zend_class_entry *php_http_params_class_entry;
zend_class_entry *php_http_params_get_class_entry(void)
{
return php_http_params_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams___construct, 0, 0, 0)
ZEND_ARG_INFO(0, params)
ZEND_ARG_INFO(0, param_sep)
ZEND_ARG_INFO(0, arg_sep)
ZEND_ARG_INFO(0, val_sep)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, __construct)
{
zval *zparams = NULL, *param_sep = NULL, *arg_sep = NULL, *val_sep = NULL;
zend_long flags = PHP_HTTP_PARAMS_DEFAULT;
zend_error_handling zeh;
zend_string *zs;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!/z/z/z/l", &zparams, ¶m_sep, &arg_sep, &val_sep, &flags), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_runtime_class_entry(), &zeh);
{
switch (ZEND_NUM_ARGS()) {
case 5:
zend_update_property_long(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), flags);
/* no break */
case 4:
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), val_sep);
/* no break */
case 3:
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), arg_sep);
/* no break */
case 2:
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), param_sep);
/* no break */
}
if (zparams) {
switch (Z_TYPE_P(zparams)) {
case IS_OBJECT:
case IS_ARRAY:
convert_to_array(zparams);
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), zparams);
break;
default:
zs = zval_get_string(zparams);
if (zs->len) {
zval tmp;
php_http_params_opts_t opts = {
{zs->val, zs->len},
php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0, &tmp)),
php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0, &tmp)),
php_http_params_separator_init(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0, &tmp)),
{{0}}, flags
};
array_init(&tmp);
php_http_params_parse(Z_ARRVAL(tmp), &opts);
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), &tmp);
zval_ptr_dtor(&tmp);
php_http_params_separator_free(opts.param);
php_http_params_separator_free(opts.arg);
php_http_params_separator_free(opts.val);
}
zend_string_release(zs);
break;
}
} else {
zval tmp;
array_init(&tmp);
zend_update_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), &tmp);
zval_ptr_dtor(&tmp);
}
}
zend_restore_error_handling(&zeh);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toArray, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, toArray)
{
zval zparams_tmp, *zparams;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
RETURN_ZVAL(zparams, 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_toString, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, toString)
{
zval *tmp, *zparams, *zpsep, *zasep, *zvsep;
zval zparams_tmp, flags_tmp, psep_tmp, asep_tmp, vsep_tmp;
zend_string *psep, *asep, *vsep;
long flags;
php_http_buffer_t buf;
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
convert_to_array_ex(zparams);
flags = zval_get_long(zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("flags"), 0, &flags_tmp));
zpsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("param_sep"), 0, &psep_tmp);
if (Z_TYPE_P(zpsep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zpsep)))) {
psep = zval_get_string(tmp);
} else {
psep = zval_get_string(zpsep);
}
zasep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("arg_sep"), 0, &asep_tmp);
if (Z_TYPE_P(zasep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zasep)))) {
asep = zval_get_string(tmp);
} else {
asep = zval_get_string(zasep);
}
zvsep = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("val_sep"), 0, &vsep_tmp);
if (Z_TYPE_P(zvsep) == IS_ARRAY && (tmp = zend_hash_get_current_data(Z_ARRVAL_P(zvsep)))) {
vsep = zval_get_string(tmp);
} else {
vsep = zval_get_string(zvsep);
}
php_http_buffer_init(&buf);
php_http_params_to_string(&buf, Z_ARRVAL_P(zparams), psep->val, psep->len, asep->val, asep->len, vsep->val, vsep->len, flags);
zend_string_release(psep);
zend_string_release(asep);
zend_string_release(vsep);
RETVAL_STR(php_http_cs2zs(buf.data, buf.used));
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetExists, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, offsetExists)
{
zend_string *name;
zval zparams_tmp, *zparam, *zparams;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) {
return;
}
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
if (Z_TYPE_P(zparams) == IS_ARRAY && (zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) {
RETVAL_BOOL(Z_TYPE_P(zparam) != IS_NULL);
} else {
RETVAL_FALSE;
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetGet, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, offsetGet)
{
zend_string *name;
zval zparams_tmp, *zparam, *zparams;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) {
return;
}
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
if (Z_TYPE_P(zparams) == IS_ARRAY && (zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) {
RETVAL_ZVAL(zparam, 1, 0);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetUnset, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, offsetUnset)
{
zend_string *name;
zval zparams_tmp, *zparams;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &name)) {
return;
}
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
if (Z_TYPE_P(zparams) == IS_ARRAY) {
zend_symtable_del(Z_ARRVAL_P(zparams), name);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpParams_offsetSet, 0, 0, 2)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpParams, offsetSet)
{
zend_string *name;
zval zparams_tmp, *zparam, *zparams, *nvalue;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &name, &nvalue)) {
return;
}
zparams = zend_read_property(php_http_params_class_entry, getThis(), ZEND_STRL("params"), 0, &zparams_tmp);
convert_to_array(zparams);
if (name->len) {
if (Z_TYPE_P(nvalue) == IS_ARRAY) {
if ((zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) {
convert_to_array(zparam);
array_join(Z_ARRVAL_P(nvalue), Z_ARRVAL_P(zparam), 0, 0);
} else {
Z_TRY_ADDREF_P(nvalue);
add_assoc_zval_ex(zparams, name->val, name->len, nvalue);
}
} else {
zval tmp;
if ((zparam = zend_symtable_find(Z_ARRVAL_P(zparams), name))) {
ZVAL_DUP(&tmp, zparam);
convert_to_array(&tmp);
} else {
array_init(&tmp);
}
Z_TRY_ADDREF_P(nvalue);
add_assoc_zval_ex(&tmp, ZEND_STRL("value"), nvalue);
add_assoc_zval_ex(zparams, name->val, name->len, &tmp);
}
} else {
zval arr;
zend_string *zs = zval_get_string(nvalue);
array_init(&arr);
add_assoc_bool_ex(&arr, ZEND_STRL("value"), 1);
add_assoc_zval_ex(zparams, zs->val, zs->len, &arr);
zend_string_release(zs);
}
}
static zend_function_entry php_http_params_methods[] = {
PHP_ME(HttpParams, __construct, ai_HttpParams___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
PHP_ME(HttpParams, toArray, ai_HttpParams_toArray, ZEND_ACC_PUBLIC)
PHP_ME(HttpParams, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpParams, __toString, toString, ai_HttpParams_toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpParams, offsetExists, ai_HttpParams_offsetExists, ZEND_ACC_PUBLIC)
PHP_ME(HttpParams, offsetUnset, ai_HttpParams_offsetUnset, ZEND_ACC_PUBLIC)
PHP_ME(HttpParams, offsetSet, ai_HttpParams_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(HttpParams, offsetGet, ai_HttpParams_offsetGet, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_params)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Params", php_http_params_methods);
php_http_params_class_entry = zend_register_internal_class(&ce);
php_http_params_class_entry->create_object = php_http_params_object_new;
zend_class_implements(php_http_params_class_entry, 1, zend_ce_arrayaccess);
zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_PARAM_SEP"), ZEND_STRL(","));
zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_ARG_SEP"), ZEND_STRL(";"));
zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("DEF_VAL_SEP"), ZEND_STRL("="));
zend_declare_class_constant_stringl(php_http_params_class_entry, ZEND_STRL("COOKIE_PARAM_SEP"), ZEND_STRL(""));
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RAW"), PHP_HTTP_PARAMS_RAW);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_ESCAPED"), PHP_HTTP_PARAMS_ESCAPED);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_URLENCODED"), PHP_HTTP_PARAMS_URLENCODED);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DIMENSION"), PHP_HTTP_PARAMS_DIMENSION);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5987"), PHP_HTTP_PARAMS_RFC5987);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_RFC5988"), PHP_HTTP_PARAMS_RFC5988);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_DEFAULT"), PHP_HTTP_PARAMS_DEFAULT);
zend_declare_class_constant_long(php_http_params_class_entry, ZEND_STRL("PARSE_QUERY"), PHP_HTTP_PARAMS_QUERY);
zend_declare_property_null(php_http_params_class_entry, ZEND_STRL("params"), ZEND_ACC_PUBLIC);
zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("param_sep"), ZEND_STRL(","), ZEND_ACC_PUBLIC);
zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("arg_sep"), ZEND_STRL(";"), ZEND_ACC_PUBLIC);
zend_declare_property_stringl(php_http_params_class_entry, ZEND_STRL("val_sep"), ZEND_STRL("="), ZEND_ACC_PUBLIC);
zend_declare_property_long(php_http_params_class_entry, ZEND_STRL("flags"), PHP_HTTP_PARAMS_DEFAULT, ZEND_ACC_PUBLIC);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_params.h 0000644 0001750 0000144 00000004621 12667772426 016520 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_PARAMS_H
#define PHP_HTTP_PARAMS_H
typedef struct php_http_params_token {
char *str;
size_t len;
} php_http_params_token_t;
#define PHP_HTTP_PARAMS_RAW 0x00
#define PHP_HTTP_PARAMS_ESCAPED 0x01
#define PHP_HTTP_PARAMS_URLENCODED 0x04
#define PHP_HTTP_PARAMS_DIMENSION 0x08
#define PHP_HTTP_PARAMS_RFC5987 0x10
#define PHP_HTTP_PARAMS_RFC5988 0x20
#define PHP_HTTP_PARAMS_QUERY (PHP_HTTP_PARAMS_URLENCODED|PHP_HTTP_PARAMS_DIMENSION)
#define PHP_HTTP_PARAMS_DEFAULT (PHP_HTTP_PARAMS_ESCAPED|PHP_HTTP_PARAMS_RFC5987)
typedef struct php_http_params_opts {
php_http_params_token_t input;
php_http_params_token_t **param;
php_http_params_token_t **arg;
php_http_params_token_t **val;
zval defval;
unsigned flags;
} php_http_params_opts_t;
PHP_HTTP_API php_http_params_opts_t *php_http_params_opts_default_get(php_http_params_opts_t *opts);
PHP_HTTP_API HashTable *php_http_params_parse(HashTable *params, const php_http_params_opts_t *opts);
PHP_HTTP_API php_http_buffer_t *php_http_params_to_string(php_http_buffer_t *buf, HashTable *params, const char *pss, size_t psl, const char *ass, size_t asl, const char *vss, size_t vsl, unsigned flags);
PHP_HTTP_API php_http_params_token_t **php_http_params_separator_init(zval *zv);
PHP_HTTP_API void php_http_params_separator_free(php_http_params_token_t **separator);
typedef php_http_object_t php_http_params_object_t;
PHP_HTTP_API zend_class_entry *php_http_params_get_class_entry(void);
PHP_MINIT_FUNCTION(http_params);
#define php_http_params_object_new php_http_object_new
#define php_http_params_object_new_ex php_http_object_new_ex
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_querystring.c 0000644 0001750 0000144 00000053545 12667772426 017635 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#include
#include
#ifdef PHP_HTTP_HAVE_ICONV
# ifndef HAVE_ICONV
# define HAVE_ICONV 1
# endif
# undef PHP_ATOM_INC
# include
#endif
static zend_class_entry *php_http_querystring_class_entry;
zend_class_entry *php_http_querystring_get_class_entry(void)
{
return php_http_querystring_class_entry;
}
#define QS_MERGE 1
static inline void php_http_querystring_set(zval *instance, zval *params, int flags)
{
zval qa;
array_init(&qa);
if (flags & QS_MERGE) {
zval old_tmp, *old = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &old_tmp);
ZVAL_DEREF(old);
if (Z_TYPE_P(old) == IS_ARRAY) {
array_copy(Z_ARRVAL_P(old), Z_ARRVAL(qa));
}
}
php_http_querystring_update(&qa, params, NULL);
zend_update_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), &qa);
zval_ptr_dtor(&qa);
}
static inline void php_http_querystring_str(zval *instance, zval *return_value)
{
zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &qa_tmp);
ZVAL_DEREF(qa);
if (Z_TYPE_P(qa) == IS_ARRAY) {
php_http_querystring_update(qa, NULL, return_value);
} else {
RETURN_EMPTY_STRING();
}
}
static inline void php_http_querystring_get(zval *instance, int type, char *name, uint name_len, zval *defval, zend_bool del, zval *return_value)
{
zval *arrval, qarray_tmp, *qarray = zend_read_property(php_http_querystring_class_entry, instance, ZEND_STRL("queryArray"), 0, &qarray_tmp);
ZVAL_DEREF(qarray);
if ((Z_TYPE_P(qarray) == IS_ARRAY) && (arrval = zend_symtable_str_find(Z_ARRVAL_P(qarray), name, name_len))) {
if (type && type != Z_TYPE_P(arrval)) {
zval tmp;
ZVAL_DUP(&tmp, arrval);
convert_to_explicit_type(&tmp, type);
RETVAL_ZVAL(&tmp, 0, 0);
} else {
RETVAL_ZVAL(arrval, 1, 0);
}
if (del) {
zval delarr;
array_init(&delarr);
add_assoc_null_ex(&delarr, name, name_len);
php_http_querystring_set(instance, &delarr, QS_MERGE);
zval_ptr_dtor(&delarr);
}
} else if(defval) {
RETURN_ZVAL(defval, 1, 0);
}
}
#ifdef PHP_HTTP_HAVE_ICONV
ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe)
{
zval *entry;
zend_string *xkey, *xstr;
php_http_arrkey_t key;
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(src), key.h, key.key, entry)
{
if (key.key) {
if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(key.key->val, key.key->len, &xkey, oe, ie)) {
php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", key.key->len, key.key->val, ie, oe);
return FAILURE;
}
}
if (Z_TYPE_P(entry) == IS_STRING) {
if (PHP_ICONV_ERR_SUCCESS != php_iconv_string(Z_STRVAL_P(entry), Z_STRLEN_P(entry), &xstr, oe, ie)) {
if (key.key) {
zend_string_release(xkey);
}
php_error_docref(NULL, E_WARNING, "Failed to convert '%.*s' from '%s' to '%s'", Z_STRLEN_P(entry), Z_STRVAL_P(entry), ie, oe);
return FAILURE;
}
if (key.key) {
add_assoc_str_ex(dst, xkey->val, xkey->len, xstr);
} else {
add_index_str(dst, key.h, xstr);
}
} else if (Z_TYPE_P(entry) == IS_ARRAY) {
zval subarray;
array_init(&subarray);
if (key.key) {
add_assoc_zval_ex(dst, xkey->val, xkey->len, &subarray);
} else {
add_index_zval(dst, key.h, &subarray);
}
if (SUCCESS != php_http_querystring_xlate(&subarray, entry, ie, oe)) {
if (key.key) {
zend_string_release(xkey);
}
return FAILURE;
}
}
if (key.key) {
zend_string_release(xkey);
}
}
ZEND_HASH_FOREACH_END();
return SUCCESS;
}
#endif /* HAVE_ICONV */
ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params)
{
php_http_querystring_set(instance, params, 0);
return SUCCESS;
}
static int apply_querystring(zval *val)
{
if (Z_TYPE_P(val) == IS_ARRAY) {
zval *zvalue;
if ((zvalue = zend_hash_str_find(Z_ARRVAL_P(val), ZEND_STRL("value")))) {
zval tmp;
ZVAL_COPY(&tmp, zvalue);
zval_dtor(val);
ZVAL_COPY_VALUE(val, &tmp);
}
}
return ZEND_HASH_APPLY_KEEP;
}
ZEND_RESULT_CODE php_http_querystring_parse(HashTable *ht, const char *str, size_t len)
{
ZEND_RESULT_CODE rv = FAILURE;
php_http_params_opts_t opts;
php_http_params_token_t psep = { ZEND_STRL("&") }, *psepp[] = { &psep, NULL };
php_http_params_token_t vsep = { ZEND_STRL("=") }, *vsepp[] = { &vsep, NULL };
const char *asi_str = NULL;
size_t asi_len = 0;
opts.input.str = estrndup(str, len);
opts.input.len = len;
opts.param = psepp;
opts.arg = NULL;
opts.val = vsepp;
opts.flags = PHP_HTTP_PARAMS_QUERY;
if (SUCCESS == php_http_ini_entry(ZEND_STRL("arg_separator.input"), &asi_str, &asi_len, 0) && asi_len) {
zval arr;
array_init_size(&arr, asi_len);
do {
add_next_index_stringl(&arr, asi_str++, 1);
} while (*asi_str);
opts.param = php_http_params_separator_init(&arr);
zval_ptr_dtor(&arr);
}
ZVAL_NULL(&opts.defval);
if (php_http_params_parse(ht, &opts)) {
zend_hash_apply(ht, apply_querystring);
rv = SUCCESS;
}
if (asi_len) {
php_http_params_separator_free(opts.param);
}
zval_ptr_dtor(&opts.defval);
efree(opts.input.str);
return rv;
}
ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *outstring)
{
/* enforce proper type */
if (Z_TYPE_P(qarray) != IS_ARRAY) {
convert_to_array(qarray);
}
/* modify qarray */
if (params) {
HashTable *ht;
php_http_arrkey_t key;
zval zv, *params_entry, *qarray_entry;
ZVAL_NULL(&zv);
/* squeeze the hash out of the zval */
if (Z_TYPE_P(params) == IS_OBJECT && instanceof_function(Z_OBJCE_P(params), php_http_querystring_class_entry)) {
zval qa_tmp, *qa = zend_read_property(php_http_querystring_class_entry, params, ZEND_STRL("queryArray"), 0, &qa_tmp);
ZVAL_DEREF(qa);
convert_to_array(qa);
ht = Z_ARRVAL_P(qa);
} else if (Z_TYPE_P(params) == IS_OBJECT || Z_TYPE_P(params) == IS_ARRAY) {
ht = HASH_OF(params);
} else {
zend_string *zs = zval_get_string(params);
array_init(&zv);
php_http_querystring_parse(Z_ARRVAL(zv), zs->val, zs->len);
zend_string_release(zs);
ht = Z_ARRVAL(zv);
}
ZEND_HASH_FOREACH_KEY_VAL_IND(ht, key.h, key.key, params_entry)
{
/* only public properties */
if (!key.key || *key.key->val) {
if (Z_TYPE_P(params_entry) == IS_NULL) {
/*
* delete
*/
if (key.key) {
zend_hash_del(Z_ARRVAL_P(qarray), key.key);
} else {
zend_hash_index_del(Z_ARRVAL_P(qarray), key.h);
}
} else if ( ((key.key) && (qarray_entry = zend_hash_find(Z_ARRVAL_P(qarray), key.key)))
|| ((!key.key) && (qarray_entry = zend_hash_index_find(Z_ARRVAL_P(qarray), key.h)))) {
/*
* update
*/
zval equal, tmp, *entry = &tmp;
ZVAL_UNDEF(&tmp);
/* recursive */
if (Z_TYPE_P(params_entry) == IS_ARRAY || Z_TYPE_P(params_entry) == IS_OBJECT) {
ZVAL_DUP(entry, qarray_entry);
convert_to_array(entry);
php_http_querystring_update(entry, params_entry, NULL);
} else if ((FAILURE == is_equal_function(&equal, qarray_entry, params_entry)) || Z_TYPE(equal) != IS_TRUE) {
Z_TRY_ADDREF_P(params_entry);
entry = params_entry;
}
if (entry) {
if (key.key) {
zend_hash_update(Z_ARRVAL_P(qarray), key.key, entry);
} else {
zend_hash_index_update(Z_ARRVAL_P(qarray), key.h, entry);
}
}
} else {
zval entry, *entry_ptr = &entry;
/*
* add
*/
if (Z_TYPE_P(params_entry) == IS_OBJECT) {
array_init(&entry);
php_http_querystring_update(&entry, params_entry, NULL);
} else {
Z_TRY_ADDREF_P(params_entry);
entry_ptr = params_entry;
}
if (key.key) {
add_assoc_zval_ex(qarray, key.key->val, key.key->len, entry_ptr);
} else {
add_index_zval(qarray, key.h, entry_ptr);
}
}
}
}
ZEND_HASH_FOREACH_END();
zval_dtor(&zv);
}
/* serialize to string */
if (outstring) {
char *s;
size_t l;
if (SUCCESS == php_http_url_encode_hash(Z_ARRVAL_P(qarray), NULL, 0, &s, &l)) {
zval_dtor(outstring);
ZVAL_STR(outstring, php_http_cs2zs(s, l));
} else {
php_error_docref(NULL, E_WARNING, "Failed to encode query string");
return FAILURE;
}
}
return SUCCESS;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___construct, 0, 0, 0)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, __construct)
{
zval *params = NULL;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z", ¶ms), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_querystring_class_entry(), &zeh);
php_http_querystring_set(getThis(), params, 0);
zend_restore_error_handling(&zeh);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getGlobalInstance, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, getGlobalInstance)
{
zval *instance, *_GET;
zend_string *zs;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
zs = zend_string_init(ZEND_STRL("instance"), 0);
instance = zend_std_get_static_property(php_http_querystring_class_entry, zs, 0);
zend_string_release(zs);
if (Z_TYPE_P(instance) == IS_OBJECT) {
RETVAL_ZVAL(instance, 1, 0);
} else if ((_GET = php_http_env_get_superglobal(ZEND_STRL("_GET")))) {
ZVAL_OBJ(return_value, php_http_querystring_object_new(php_http_querystring_class_entry));
ZVAL_MAKE_REF(_GET);
zend_update_property(php_http_querystring_class_entry, return_value, ZEND_STRL("queryArray"), _GET);
zend_update_static_property(php_http_querystring_class_entry, ZEND_STRL("instance"), return_value);
} else {
php_http_throw(unexpected_val, "Could not acquire reference to superglobal GET array", NULL);
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_getIterator, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, getIterator)
{
zval qa_tmp, *qa;
php_http_expect(SUCCESS == zend_parse_parameters_none(), invalid_arg, return);
qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
object_init_ex(return_value, spl_ce_RecursiveArrayIterator);
zend_call_method_with_1_params(return_value, spl_ce_RecursiveArrayIterator, NULL, "__construct", NULL, qa);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toString, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, toString)
{
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
php_http_querystring_str(getThis(), return_value);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_toArray, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, toArray)
{
zval zqa_tmp, *zqa;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
zqa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &zqa_tmp);
RETURN_ZVAL(zqa, 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_get, 0, 0, 0)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, defval)
ZEND_ARG_INFO(0, delete)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, get)
{
char *name_str = NULL;
size_t name_len = 0;
zend_long type = 0;
zend_bool del = 0;
zval *ztype = NULL, *defval = NULL;
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|szzb", &name_str, &name_len, &ztype, &defval, &del)) {
if (name_str && name_len) {
if (ztype) {
if (Z_TYPE_P(ztype) == IS_LONG) {
type = Z_LVAL_P(ztype);
} else if(Z_TYPE_P(ztype) == IS_STRING) {
switch (Z_STRVAL_P(ztype)[0]) {
case 'B':
case 'b': type = PHP_HTTP_QUERYSTRING_TYPE_BOOL; break;
case 'L':
case 'l':
case 'I':
case 'i': type = PHP_HTTP_QUERYSTRING_TYPE_INT; break;
case 'd':
case 'D':
case 'F':
case 'f': type = PHP_HTTP_QUERYSTRING_TYPE_FLOAT; break;
case 'S':
case 's': type = PHP_HTTP_QUERYSTRING_TYPE_STRING; break;
case 'A':
case 'a': type = PHP_HTTP_QUERYSTRING_TYPE_ARRAY; break;
case 'O':
case 'o': type = PHP_HTTP_QUERYSTRING_TYPE_OBJECT; break;
}
}
}
php_http_querystring_get(getThis(), type, name_str, name_len, defval, del, return_value);
} else {
php_http_querystring_str(getThis(), return_value);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_set, 0, 0, 1)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, set)
{
zval *params;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶ms)) {
return;
}
php_http_querystring_set(getThis(), params, QS_MERGE);
RETVAL_ZVAL(getThis(), 1, 0);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_mod, 0, 0, 0)
ZEND_ARG_INFO(0, params)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, mod)
{
zval qa_tmp, *params, *instance = getThis();
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z", ¶ms), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_querystring_class_entry(), &zeh);
ZVAL_OBJ(return_value, Z_OBJ_HT_P(instance)->clone_obj(instance));
/* make sure we do not inherit the reference to _GET */
SEPARATE_ZVAL(zend_read_property(Z_OBJCE_P(return_value), return_value, ZEND_STRL("queryArray"), 0, &qa_tmp));
php_http_querystring_set(return_value, params, QS_MERGE);
zend_restore_error_handling(&zeh);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString___getter, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_ARG_INFO(0, defval)
ZEND_ARG_INFO(0, delete)
ZEND_END_ARG_INFO();
#define PHP_HTTP_QUERYSTRING_GETTER(method, TYPE) \
PHP_METHOD(HttpQueryString, method) \
{ \
char *name; \
size_t name_len; \
zval *defval = NULL; \
zend_bool del = 0; \
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "s|zb", &name, &name_len, &defval, &del)) { \
php_http_querystring_get(getThis(), TYPE, name, name_len, defval, del, return_value); \
} \
}
PHP_HTTP_QUERYSTRING_GETTER(getBool, _IS_BOOL);
PHP_HTTP_QUERYSTRING_GETTER(getInt, IS_LONG);
PHP_HTTP_QUERYSTRING_GETTER(getFloat, IS_DOUBLE);
PHP_HTTP_QUERYSTRING_GETTER(getString, IS_STRING);
PHP_HTTP_QUERYSTRING_GETTER(getArray, IS_ARRAY);
PHP_HTTP_QUERYSTRING_GETTER(getObject, IS_OBJECT);
#ifdef PHP_HTTP_HAVE_ICONV
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_xlate, 0, 0, 2)
ZEND_ARG_INFO(0, from_encoding)
ZEND_ARG_INFO(0, to_encoding)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, xlate)
{
char *ie, *oe;
size_t ie_len, oe_len;
zval na, qa_tmp, *qa;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &ie, &ie_len, &oe, &oe_len), invalid_arg, return);
array_init(&na);
qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
ZVAL_DEREF(qa);
convert_to_array(qa);
php_http_expect(SUCCESS == php_http_querystring_xlate(&na, qa, ie, oe), bad_conversion,
zval_ptr_dtor(&na);
return;
);
php_http_querystring_set(getThis(), &na, 0);
RETVAL_ZVAL(getThis(), 1, 0);
zval_ptr_dtor(&na);
}
#endif /* HAVE_ICONV */
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_serialize, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, serialize)
{
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
php_http_querystring_str(getThis(), return_value);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_unserialize, 0, 0, 1)
ZEND_ARG_INFO(0, serialized)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, unserialize)
{
zval *serialized;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "z", &serialized)) {
return;
}
if (Z_TYPE_P(serialized) == IS_STRING) {
php_http_querystring_set(getThis(), serialized, 0);
} else {
php_error_docref(NULL, E_WARNING, "Expected a string as parameter");
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetGet, 0, 0, 1)
ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, offsetGet)
{
zend_string *offset;
zval *value, qa_tmp, *qa;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) {
return;
}
qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
ZVAL_DEREF(qa);
if (Z_TYPE_P(qa) == IS_ARRAY) {
if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) {
RETVAL_ZVAL(value, 1, 0);
}
}
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetSet, 0, 0, 2)
ZEND_ARG_INFO(0, offset)
ZEND_ARG_INFO(0, value)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, offsetSet)
{
zend_string *offset;
zval *value, param, znull;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "Sz", &offset, &value)) {
return;
}
array_init_size(¶m, 1);
/* unset first */
ZVAL_NULL(&znull);
zend_symtable_update(Z_ARRVAL(param), offset, &znull);
php_http_querystring_set(getThis(), ¶m, QS_MERGE);
/* then update, else QS_MERGE would merge sub-arrrays */
Z_TRY_ADDREF_P(value);
zend_symtable_update(Z_ARRVAL(param), offset, value);
php_http_querystring_set(getThis(), ¶m, QS_MERGE);
zval_ptr_dtor(¶m);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetExists, 0, 0, 1)
ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, offsetExists)
{
zend_string *offset;
zval *value, qa_tmp, *qa;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) {
return;
}
qa = zend_read_property(php_http_querystring_class_entry, getThis(), ZEND_STRL("queryArray"), 0, &qa_tmp);
ZVAL_DEREF(qa);
if (Z_TYPE_P(qa) == IS_ARRAY) {
if ((value = zend_symtable_find(Z_ARRVAL_P(qa), offset))) {
RETURN_BOOL(Z_TYPE_P(value) != IS_NULL);
}
}
RETURN_FALSE;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpQueryString_offsetUnset, 0, 0, 1)
ZEND_ARG_INFO(0, offset)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpQueryString, offsetUnset)
{
zend_string *offset;
zval param, znull;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "S", &offset)) {
return;
}
array_init(¶m);
ZVAL_NULL(&znull);
zend_symtable_update(Z_ARRVAL(param), offset, &znull);
php_http_querystring_set(getThis(), ¶m, QS_MERGE);
zval_ptr_dtor(¶m);
}
static zend_function_entry php_http_querystring_methods[] = {
PHP_ME(HttpQueryString, __construct, ai_HttpQueryString___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR|ZEND_ACC_FINAL)
PHP_ME(HttpQueryString, toArray, ai_HttpQueryString_toArray, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpQueryString, __toString, toString, ai_HttpQueryString_toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, get, ai_HttpQueryString_get, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, set, ai_HttpQueryString_set, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, mod, ai_HttpQueryString_mod, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getBool, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getInt, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getFloat, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getString, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getArray, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getObject, ai_HttpQueryString___getter, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getIterator, ai_HttpQueryString_getIterator, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, getGlobalInstance, ai_HttpQueryString_getGlobalInstance, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
#ifdef PHP_HTTP_HAVE_ICONV
PHP_ME(HttpQueryString, xlate, ai_HttpQueryString_xlate, ZEND_ACC_PUBLIC)
#endif
/* Implements Serializable */
PHP_ME(HttpQueryString, serialize, ai_HttpQueryString_serialize, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, unserialize, ai_HttpQueryString_unserialize, ZEND_ACC_PUBLIC)
/* Implements ArrayAccess */
PHP_ME(HttpQueryString, offsetGet, ai_HttpQueryString_offsetGet, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, offsetSet, ai_HttpQueryString_offsetSet, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, offsetExists, ai_HttpQueryString_offsetExists, ZEND_ACC_PUBLIC)
PHP_ME(HttpQueryString, offsetUnset, ai_HttpQueryString_offsetUnset, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_querystring)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "QueryString", php_http_querystring_methods);
php_http_querystring_class_entry = zend_register_internal_class(&ce);
php_http_querystring_class_entry->create_object = php_http_querystring_object_new;
zend_class_implements(php_http_querystring_class_entry, 3, zend_ce_serializable, zend_ce_arrayaccess, zend_ce_aggregate);
zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE));
zend_declare_property_null(php_http_querystring_class_entry, ZEND_STRL("queryArray"), ZEND_ACC_PRIVATE);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_BOOL"), PHP_HTTP_QUERYSTRING_TYPE_BOOL);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_INT"), PHP_HTTP_QUERYSTRING_TYPE_INT);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_FLOAT"), PHP_HTTP_QUERYSTRING_TYPE_FLOAT);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_STRING"), PHP_HTTP_QUERYSTRING_TYPE_STRING);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_ARRAY"), PHP_HTTP_QUERYSTRING_TYPE_ARRAY);
zend_declare_class_constant_long(php_http_querystring_class_entry, ZEND_STRL("TYPE_OBJECT"), PHP_HTTP_QUERYSTRING_TYPE_OBJECT);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_querystring.h 0000644 0001750 0000144 00000003530 12667772426 017627 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_QUERYSTRING_H
#define PHP_HTTP_QUERYSTRING_H
#ifdef PHP_HTTP_HAVE_ICONV
PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_xlate(zval *dst, zval *src, const char *ie, const char *oe);
#endif /* PHP_HTTP_HAVE_ICONV */
PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_update(zval *qarray, zval *params, zval *qstring);
PHP_HTTP_API ZEND_RESULT_CODE php_http_querystring_ctor(zval *instance, zval *params);
typedef php_http_object_t php_http_querystring_object_t;
#define PHP_HTTP_QUERYSTRING_TYPE_BOOL _IS_BOOL
#define PHP_HTTP_QUERYSTRING_TYPE_INT IS_LONG
#define PHP_HTTP_QUERYSTRING_TYPE_FLOAT IS_DOUBLE
#define PHP_HTTP_QUERYSTRING_TYPE_STRING IS_STRING
#define PHP_HTTP_QUERYSTRING_TYPE_ARRAY IS_ARRAY
#define PHP_HTTP_QUERYSTRING_TYPE_OBJECT IS_OBJECT
PHP_HTTP_API zend_class_entry *php_http_querystring_get_class_entry(void);
PHP_MINIT_FUNCTION(http_querystring);
#define php_http_querystring_object_new php_http_object_new
#define php_http_querystring_object_new_ex php_http_object_new_ex
#endif /* PHP_HTTP_QUERYSTRING_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_response_codes.h 0000644 0001750 0000144 00000007041 12667772426 020247 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2015, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_RESPONSE_CODE
# define PHP_HTTP_RESPONSE_CODE(code, status)
#endif
PHP_HTTP_RESPONSE_CODE(100, "Continue")
PHP_HTTP_RESPONSE_CODE(101, "Switching Protocols")
PHP_HTTP_RESPONSE_CODE(102, "Processing")
PHP_HTTP_RESPONSE_CODE(200, "OK")
PHP_HTTP_RESPONSE_CODE(201, "Created")
PHP_HTTP_RESPONSE_CODE(202, "Accepted")
PHP_HTTP_RESPONSE_CODE(203, "Non-Authoritative Information")
PHP_HTTP_RESPONSE_CODE(204, "No Content")
PHP_HTTP_RESPONSE_CODE(205, "Reset Content")
PHP_HTTP_RESPONSE_CODE(206, "Partial Content")
PHP_HTTP_RESPONSE_CODE(207, "Multi-Status")
PHP_HTTP_RESPONSE_CODE(208, "Already Reported")
PHP_HTTP_RESPONSE_CODE(226, "IM Used")
PHP_HTTP_RESPONSE_CODE(300, "Multiple Choices")
PHP_HTTP_RESPONSE_CODE(301, "Moved Permanently")
PHP_HTTP_RESPONSE_CODE(302, "Found")
PHP_HTTP_RESPONSE_CODE(303, "See Other")
PHP_HTTP_RESPONSE_CODE(304, "Not Modified")
PHP_HTTP_RESPONSE_CODE(305, "Use Proxy")
PHP_HTTP_RESPONSE_CODE(307, "Temporary Redirect")
PHP_HTTP_RESPONSE_CODE(308, "Permanent Redirect")
PHP_HTTP_RESPONSE_CODE(400, "Bad Request")
PHP_HTTP_RESPONSE_CODE(401, "Unauthorized")
PHP_HTTP_RESPONSE_CODE(402, "Payment Required")
PHP_HTTP_RESPONSE_CODE(403, "Forbidden")
PHP_HTTP_RESPONSE_CODE(404, "Not Found")
PHP_HTTP_RESPONSE_CODE(405, "Method Not Allowed")
PHP_HTTP_RESPONSE_CODE(406, "Not Acceptable")
PHP_HTTP_RESPONSE_CODE(407, "Proxy Authentication Required")
PHP_HTTP_RESPONSE_CODE(408, "Request Timeout")
PHP_HTTP_RESPONSE_CODE(409, "Conflict")
PHP_HTTP_RESPONSE_CODE(410, "Gone")
PHP_HTTP_RESPONSE_CODE(411, "Length Required")
PHP_HTTP_RESPONSE_CODE(412, "Precondition Failed")
PHP_HTTP_RESPONSE_CODE(413, "Request Entity Too Large")
PHP_HTTP_RESPONSE_CODE(414, "Request URI Too Long")
PHP_HTTP_RESPONSE_CODE(415, "Unsupported Media Type")
PHP_HTTP_RESPONSE_CODE(416, "Requested Range Not Satisfiable")
PHP_HTTP_RESPONSE_CODE(417, "Expectation Failed")
PHP_HTTP_RESPONSE_CODE(422, "Unprocessible Entity")
PHP_HTTP_RESPONSE_CODE(423, "Locked")
PHP_HTTP_RESPONSE_CODE(424, "Failed Dependency")
PHP_HTTP_RESPONSE_CODE(426, "Upgrade Required")
PHP_HTTP_RESPONSE_CODE(428, "Precondition Required")
PHP_HTTP_RESPONSE_CODE(429, "Too Many Requests")
PHP_HTTP_RESPONSE_CODE(431, "Request Header Fields Too Large")
PHP_HTTP_RESPONSE_CODE(500, "Internal Server Error")
PHP_HTTP_RESPONSE_CODE(501, "Not Implemented")
PHP_HTTP_RESPONSE_CODE(502, "Bad Gateway")
PHP_HTTP_RESPONSE_CODE(503, "Service Unavailable")
PHP_HTTP_RESPONSE_CODE(504, "Gateway Timeout")
PHP_HTTP_RESPONSE_CODE(505, "HTTP Version Not Supported")
PHP_HTTP_RESPONSE_CODE(506, "Variant Also Negotiates")
PHP_HTTP_RESPONSE_CODE(507, "Insufficient Storage")
PHP_HTTP_RESPONSE_CODE(508, "Loop Detected")
PHP_HTTP_RESPONSE_CODE(510, "Not Extended")
PHP_HTTP_RESPONSE_CODE(511, "Network Authentication Required")
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_url.c 0000644 0001750 0000144 00000143125 12667772426 016035 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
#if PHP_HTTP_HAVE_IDN2
# include
#elif PHP_HTTP_HAVE_IDN
# include
#endif
#ifdef PHP_HTTP_HAVE_WCHAR
# include
# include
#endif
#ifdef HAVE_ARPA_INET_H
# include
#endif
#include "php_http_utf8.h"
static inline char *localhostname(void)
{
char hostname[1024] = {0};
#ifdef PHP_WIN32
if (SUCCESS == gethostname(hostname, lenof(hostname))) {
return estrdup(hostname);
}
#elif defined(HAVE_GETHOSTNAME)
if (SUCCESS == gethostname(hostname, lenof(hostname))) {
# if defined(HAVE_GETDOMAINNAME)
size_t hlen = strlen(hostname);
if (hlen <= lenof(hostname) - lenof("(none)")) {
hostname[hlen++] = '.';
if (SUCCESS == getdomainname(&hostname[hlen], lenof(hostname) - hlen)) {
if (!strcmp(&hostname[hlen], "(none)")) {
hostname[hlen - 1] = '\0';
}
return estrdup(hostname);
}
}
# endif
if (strcmp(hostname, "(none)")) {
return estrdup(hostname);
}
}
#endif
return estrndup("localhost", lenof("localhost"));
}
#define url(buf) ((php_http_url_t *) (buf).data)
static php_http_url_t *php_http_url_from_env(void)
{
zval *https, *zhost, *zport;
long port;
php_http_buffer_t buf;
php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
php_http_buffer_account(&buf, sizeof(php_http_url_t));
memset(buf.data, 0, buf.used);
/* scheme */
url(buf)->scheme = &buf.data[buf.used];
https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1);
if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
php_http_buffer_append(&buf, "https", sizeof("https"));
} else {
php_http_buffer_append(&buf, "http", sizeof("http"));
}
/* host */
url(buf)->host = &buf.data[buf.used];
if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1)) ||
(zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1)) ||
(zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1)))) && Z_STRLEN_P(zhost)) {
size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.");
php_http_buffer_append(&buf, Z_STRVAL_P(zhost), stop_at);
php_http_buffer_append(&buf, "", 1);
} else {
char *host_str = localhostname();
php_http_buffer_append(&buf, host_str, strlen(host_str) + 1);
efree(host_str);
}
/* port */
zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1);
if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) {
url(buf)->port = port;
}
/* path */
if (SG(request_info).request_uri && SG(request_info).request_uri[0]) {
const char *q = strchr(SG(request_info).request_uri, '?');
url(buf)->path = &buf.data[buf.used];
if (q) {
php_http_buffer_append(&buf, SG(request_info).request_uri, q - SG(request_info).request_uri);
php_http_buffer_append(&buf, "", 1);
} else {
php_http_buffer_append(&buf, SG(request_info).request_uri, strlen(SG(request_info).request_uri) + 1);
}
}
/* query */
if (SG(request_info).query_string && SG(request_info).query_string[0]) {
url(buf)->query = &buf.data[buf.used];
php_http_buffer_append(&buf, SG(request_info).query_string, strlen(SG(request_info).query_string) + 1);
}
return url(buf);
}
#define url_isset(u,n) \
((u)&&(u)->n)
#define url_append(buf, append) do { \
char *_ptr = (buf)->data; \
php_http_url_t *_url = (php_http_url_t *) _ptr, _mem = *_url; \
append; \
/* relocate */ \
if (_ptr != (buf)->data) { \
ptrdiff_t diff = (buf)->data - _ptr; \
_url = (php_http_url_t *) (buf)->data; \
if (_mem.scheme) _url->scheme += diff; \
if (_mem.user) _url->user += diff; \
if (_mem.pass) _url->pass += diff; \
if (_mem.host) _url->host += diff; \
if (_mem.path) _url->path += diff; \
if (_mem.query) _url->query += diff; \
if (_mem.fragment) _url->fragment += diff; \
} \
} while (0)
#define url_copy(n) do { \
if (url_isset(new_url, n)) { \
url(buf)->n = &buf.data[buf.used]; \
url_append(&buf, php_http_buffer_append(&buf, new_url->n, strlen(new_url->n) + 1)); \
} else if (url_isset(old_url, n)) { \
url(buf)->n = &buf.data[buf.used]; \
url_append(&buf, php_http_buffer_append(&buf, old_url->n, strlen(old_url->n) + 1)); \
} \
} while (0)
php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags)
{
php_http_url_t *tmp_url = NULL;
php_http_buffer_t buf;
php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
php_http_buffer_account(&buf, sizeof(php_http_url_t));
memset(buf.data, 0, buf.used);
/* set from env if requested */
if (flags & PHP_HTTP_URL_FROM_ENV) {
php_http_url_t *env_url = php_http_url_from_env();
old_url = tmp_url = php_http_url_mod(env_url, old_url, flags ^ PHP_HTTP_URL_FROM_ENV);
php_http_url_free(&env_url);
}
url_copy(scheme);
if (!(flags & PHP_HTTP_URL_STRIP_USER)) {
url_copy(user);
}
if (!(flags & PHP_HTTP_URL_STRIP_PASS)) {
url_copy(pass);
}
url_copy(host);
if (!(flags & PHP_HTTP_URL_STRIP_PORT)) {
url(buf)->port = url_isset(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
}
if (!(flags & PHP_HTTP_URL_STRIP_PATH)) {
if ((flags & PHP_HTTP_URL_JOIN_PATH) && url_isset(old_url, path) && url_isset(new_url, path) && *new_url->path != '/') {
size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
char *path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
strcat(path, old_url->path);
if (path[old_path_len - 1] != '/') {
php_dirname(path, old_path_len);
strcat(path, "/");
}
strcat(path, new_url->path);
url(buf)->path = &buf.data[buf.used];
if (path[0] != '/') {
url_append(&buf, php_http_buffer_append(&buf, "/", 1));
}
url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
efree(path);
} else {
const char *path = NULL;
if (url_isset(new_url, path)) {
path = new_url->path;
} else if (url_isset(old_url, path)) {
path = old_url->path;
}
if (path) {
url(buf)->path = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
}
}
}
if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) {
if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) {
zval qarr, qstr;
array_init(&qarr);
ZVAL_STRING(&qstr, old_url->query);
php_http_querystring_update(&qarr, &qstr, NULL);
zval_ptr_dtor(&qstr);
ZVAL_STRING(&qstr, new_url->query);
php_http_querystring_update(&qarr, &qstr, NULL);
zval_ptr_dtor(&qstr);
ZVAL_NULL(&qstr);
php_http_querystring_update(&qarr, NULL, &qstr);
url(buf)->query = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1));
zval_dtor(&qstr);
zval_dtor(&qarr);
} else {
url_copy(query);
}
}
if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
url_copy(fragment);
}
/* done with copy & combine & strip */
if (flags & PHP_HTTP_URL_FROM_ENV) {
/* free old_url we tainted above */
php_http_url_free(&tmp_url);
}
/* replace directory references if path is not a single slash */
if ((flags & PHP_HTTP_URL_SANITIZE_PATH)
&& url(buf)->path
&& url(buf)->path[0] && url(buf)->path[1]) {
char *ptr, *end = url(buf)->path + strlen(url(buf)->path) + 1;
for (ptr = strchr(url(buf)->path, '/'); ptr; ptr = strchr(ptr, '/')) {
switch (ptr[1]) {
case '/':
memmove(&ptr[1], &ptr[2], end - &ptr[2]);
break;
case '.':
switch (ptr[2]) {
case '\0':
ptr[1] = '\0';
break;
case '/':
memmove(&ptr[1], &ptr[3], end - &ptr[3]);
break;
case '.':
if (ptr[3] == '/') {
char *pos = &ptr[4];
while (ptr != url(buf)->path) {
if (*--ptr == '/') {
break;
}
}
memmove(&ptr[1], pos, end - pos);
break;
} else if (!ptr[3]) {
/* .. at the end */
ptr[1] = '\0';
}
/* no break */
default:
/* something else */
++ptr;
break;
}
break;
default:
++ptr;
break;
}
}
}
/* unset default ports */
if (url(buf)->port) {
if ( ((url(buf)->port == 80) && url(buf)->scheme && !strcmp(url(buf)->scheme, "http"))
|| ((url(buf)->port ==443) && url(buf)->scheme && !strcmp(url(buf)->scheme, "https"))
) {
url(buf)->port = 0;
}
}
return url(buf);
}
char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent)
{
php_http_buffer_t buf;
php_http_buffer_init_ex(&buf, PHP_HTTP_BUFFER_DEFAULT_SIZE, persistent ?
PHP_HTTP_BUFFER_INIT_PERSISTENT : 0);
if (url->scheme && *url->scheme) {
php_http_buffer_appendl(&buf, url->scheme);
php_http_buffer_appends(&buf, "://");
} else if ((url->user && *url->user) || (url->host && *url->host)) {
php_http_buffer_appends(&buf, "//");
}
if (url->user && *url->user) {
php_http_buffer_appendl(&buf, url->user);
if (url->pass && *url->pass) {
php_http_buffer_appends(&buf, ":");
php_http_buffer_appendl(&buf, url->pass);
}
php_http_buffer_appends(&buf, "@");
}
if (url->host && *url->host) {
php_http_buffer_appendl(&buf, url->host);
if (url->port) {
php_http_buffer_appendf(&buf, ":%hu", url->port);
}
}
if (url->path && *url->path) {
if (*url->path != '/') {
php_http_buffer_appends(&buf, "/");
}
php_http_buffer_appendl(&buf, url->path);
} else if (buf.used) {
php_http_buffer_appends(&buf, "/");
}
if (url->query && *url->query) {
php_http_buffer_appends(&buf, "?");
php_http_buffer_appendl(&buf, url->query);
}
if (url->fragment && *url->fragment) {
php_http_buffer_appends(&buf, "#");
php_http_buffer_appendl(&buf, url->fragment);
}
php_http_buffer_shrink(&buf);
php_http_buffer_fix(&buf);
if (url_len) {
*url_len = buf.used;
}
if (url_str) {
*url_str = buf.data;
}
return buf.data;
}
char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len)
{
php_http_buffer_t buf;
php_http_buffer_init(&buf);
if (url->user && *url->user) {
php_http_buffer_appendl(&buf, url->user);
if (url->pass && *url->pass) {
php_http_buffer_appends(&buf, ":");
php_http_buffer_appendl(&buf, url->pass);
}
php_http_buffer_appends(&buf, "@");
}
if (url->host && *url->host) {
php_http_buffer_appendl(&buf, url->host);
if (url->port) {
php_http_buffer_appendf(&buf, ":%hu", url->port);
}
}
php_http_buffer_shrink(&buf);
php_http_buffer_fix(&buf);
if (url_len) {
*url_len = buf.used;
}
if (url_str) {
*url_str = buf.data;
}
return buf.data;
}
php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags)
{
zend_string *zs;
php_http_url_t *purl;
switch (Z_TYPE_P(value)) {
case IS_ARRAY:
case IS_OBJECT:
purl = php_http_url_from_struct(HASH_OF(value));
break;
default:
zs = zval_get_string(value);
purl = php_http_url_parse(zs->val, zs->len, flags);
zend_string_release(zs);
}
return purl;
}
php_http_url_t *php_http_url_from_struct(HashTable *ht)
{
zval *e;
php_http_buffer_t buf;
php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
php_http_buffer_account(&buf, sizeof(php_http_url_t));
memset(buf.data, 0, buf.used);
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("scheme")))) {
zend_string *zs = zval_get_string(e);
url(buf)->scheme = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("user")))) {
zend_string *zs = zval_get_string(e);
url(buf)->user = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("pass")))) {
zend_string *zs = zval_get_string(e);
url(buf)->pass = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("host")))) {
zend_string *zs = zval_get_string(e);
url(buf)->host = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("port")))) {
url(buf)->port = (unsigned short) zval_get_long(e);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("path")))) {
zend_string *zs = zval_get_string(e);
url(buf)->path = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("query")))) {
zend_string *zs = zval_get_string(e);
url(buf)->query = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
if ((e = zend_hash_str_find_ind(ht, ZEND_STRL("fragment")))) {
zend_string *zs = zval_get_string(e);
url(buf)->fragment = &buf.data[buf.used];
url_append(&buf, php_http_buffer_append(&buf, zs->val, zs->len + 1));
zend_string_release(zs);
}
return url(buf);
}
HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct)
{
HashTable *ht;
zval tmp;
if (strct) {
switch (Z_TYPE_P(strct)) {
default:
zval_dtor(strct);
array_init(strct);
/* no break */
case IS_ARRAY:
case IS_OBJECT:
ht = HASH_OF(strct);
break;
}
} else {
ALLOC_HASHTABLE(ht);
zend_hash_init(ht, 8, NULL, ZVAL_PTR_DTOR, 0);
}
#define url_struct_add(part) \
if (Z_TYPE_P(strct) == IS_ARRAY) { \
zend_hash_str_update(Z_ARRVAL_P(strct), part, lenof(part), &tmp); \
} else { \
zend_update_property(Z_OBJCE_P(strct), strct, part, lenof(part), &tmp); \
zval_ptr_dtor(&tmp); \
}
if (url) {
if (url->scheme) {
ZVAL_STRING(&tmp, url->scheme);
url_struct_add("scheme");
}
if (url->user) {
ZVAL_STRING(&tmp, url->user);
url_struct_add("user");
}
if (url->pass) {
ZVAL_STRING(&tmp, url->pass);
url_struct_add("pass");
}
if (url->host) {
ZVAL_STRING(&tmp, url->host);
url_struct_add("host");
}
if (url->port) {
ZVAL_LONG(&tmp, url->port);
url_struct_add("port");
}
if (url->path) {
ZVAL_STRING(&tmp, url->path);
url_struct_add("path");
}
if (url->query) {
ZVAL_STRING(&tmp, url->query);
url_struct_add("query");
}
if (url->fragment) {
ZVAL_STRING(&tmp, url->fragment);
url_struct_add("fragment");
}
}
return ht;
}
ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len)
{
const char *arg_sep_str = "&";
size_t arg_sep_len = 1;
php_http_buffer_t *qstr = php_http_buffer_new();
php_http_url_argsep(&arg_sep_str, &arg_sep_len);
if (SUCCESS != php_http_url_encode_hash_ex(hash, qstr, arg_sep_str, arg_sep_len, "=", 1, pre_encoded_str, pre_encoded_len)) {
php_http_buffer_free(&qstr);
return FAILURE;
}
php_http_buffer_data(qstr, encoded_str, encoded_len);
php_http_buffer_free(&qstr);
return SUCCESS;
}
ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len)
{
if (pre_encoded_len && pre_encoded_str) {
php_http_buffer_append(qstr, pre_encoded_str, pre_encoded_len);
}
if (!php_http_params_to_string(qstr, hash, arg_sep_str, arg_sep_len, "", 0, val_sep_str, val_sep_len, PHP_HTTP_PARAMS_QUERY)) {
return FAILURE;
}
return SUCCESS;
}
struct parse_state {
php_http_url_t url;
const char *ptr;
const char *end;
size_t maxlen;
off_t offset;
unsigned flags;
char buffer[1]; /* last member */
};
void php_http_url_free(php_http_url_t **url)
{
if (*url) {
efree(*url);
*url = NULL;
}
}
php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent)
{
php_http_url_t *cpy;
const char *end = NULL, *url_ptr = (const char *) url;
char *cpy_ptr;
end = MAX(url->scheme, end);
end = MAX(url->pass, end);
end = MAX(url->user, end);
end = MAX(url->host, end);
end = MAX(url->path, end);
end = MAX(url->query, end);
end = MAX(url->fragment, end);
if (end) {
end += strlen(end) + 1;
cpy_ptr = pecalloc(1, end - url_ptr, persistent);
cpy = (php_http_url_t *) cpy_ptr;
memcpy(cpy_ptr + sizeof(*cpy), url_ptr + sizeof(*url), end - url_ptr - sizeof(*url));
cpy->scheme = url->scheme ? cpy_ptr + (url->scheme - url_ptr) : NULL;
cpy->pass = url->pass ? cpy_ptr + (url->pass - url_ptr) : NULL;
cpy->user = url->user ? cpy_ptr + (url->user - url_ptr) : NULL;
cpy->host = url->host ? cpy_ptr + (url->host - url_ptr) : NULL;
cpy->path = url->path ? cpy_ptr + (url->path - url_ptr) : NULL;
cpy->query = url->query ? cpy_ptr + (url->query - url_ptr) : NULL;
cpy->fragment = url->fragment ? cpy_ptr + (url->fragment - url_ptr) : NULL;
} else {
cpy = ecalloc(1, sizeof(*url));
}
cpy->port = url->port;
return cpy;
}
static size_t parse_mb_utf8(unsigned *wc, const char *ptr, const char *end)
{
unsigned wchar;
size_t consumed = utf8towc(&wchar, (const unsigned char *) ptr, end - ptr);
if (!consumed || consumed == (size_t) -1) {
return 0;
}
if (wc) {
*wc = wchar;
}
return consumed;
}
#ifdef PHP_HTTP_HAVE_WCHAR
static size_t parse_mb_loc(unsigned *wc, const char *ptr, const char *end)
{
wchar_t wchar;
size_t consumed = 0;
#if defined(HAVE_MBRTOWC)
mbstate_t ps;
memset(&ps, 0, sizeof(ps));
consumed = mbrtowc(&wchar, ptr, end - ptr, &ps);
#elif defined(HAVE_MBTOWC)
consumed = mbtowc(&wchar, ptr, end - ptr);
#endif
if (!consumed || consumed == (size_t) -1) {
return 0;
}
if (wc) {
*wc = wchar;
}
return consumed;
}
#endif
typedef enum parse_mb_what {
PARSE_SCHEME,
PARSE_USERINFO,
PARSE_HOSTINFO,
PARSE_PATH,
PARSE_QUERY,
PARSE_FRAGMENT
} parse_mb_what_t;
static const char * const parse_what[] = {
"scheme",
"userinfo",
"hostinfo",
"path",
"query",
"fragment"
};
static const char parse_xdigits[] = "0123456789ABCDEF";
static size_t parse_mb(struct parse_state *state, parse_mb_what_t what, const char *ptr, const char *end, const char *begin, zend_bool silent)
{
unsigned wchar;
size_t consumed = 0;
if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
consumed = parse_mb_utf8(&wchar, ptr, end);
}
#ifdef PHP_HTTP_HAVE_WCHAR
else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
consumed = parse_mb_loc(&wchar, ptr, end);
}
#endif
while (consumed) {
if (!(state->flags & PHP_HTTP_URL_PARSE_TOPCT) || what == PARSE_HOSTINFO || what == PARSE_SCHEME) {
if (what == PARSE_HOSTINFO && (state->flags & PHP_HTTP_URL_PARSE_TOIDN)) {
/* idna */
} else if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
if (!isualnum(wchar)) {
break;
}
#ifdef PHP_HTTP_HAVE_WCHAR
} else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
if (!iswalnum(wchar)) {
break;
}
#endif
}
PHP_HTTP_DUFF(consumed, state->buffer[state->offset++] = *ptr++);
} else {
int i = 0;
PHP_HTTP_DUFF(consumed,
state->buffer[state->offset++] = '%';
state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) >> 4];
state->buffer[state->offset++] = parse_xdigits[((unsigned char) ptr[i]) & 0xf];
++i;
);
}
return consumed;
}
if (!silent) {
if (consumed) {
php_error_docref(NULL, E_WARNING,
"Failed to parse %s; unexpected multibyte sequence 0x%x at pos %u in '%s'",
parse_what[what], wchar, (unsigned) (ptr - begin), begin);
} else {
php_error_docref(NULL, E_WARNING,
"Failed to parse %s; unexpected byte 0x%02x at pos %u in '%s'",
parse_what[what], (unsigned char) *ptr, (unsigned) (ptr - begin), begin);
}
}
return 0;
}
static ZEND_RESULT_CODE parse_userinfo(struct parse_state *state, const char *ptr)
{
size_t mb;
const char *password = NULL, *end = state->ptr, *tmp = ptr;
state->url.user = &state->buffer[state->offset];
do {
switch (*ptr) {
case ':':
if (password) {
php_error_docref(NULL, E_WARNING,
"Failed to parse password; duplicate ':' at pos %u in '%s'",
(unsigned) (ptr - tmp), tmp);
return FAILURE;
}
password = ptr + 1;
state->buffer[state->offset++] = 0;
state->url.pass = &state->buffer[state->offset];
break;
case '%':
if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) {
php_error_docref(NULL, E_WARNING,
"Failed to parse userinfo; invalid percent encoding at pos %u in '%s'",
(unsigned) (ptr - tmp), tmp);
return FAILURE;
}
state->buffer[state->offset++] = *ptr++;
state->buffer[state->offset++] = *ptr++;
state->buffer[state->offset++] = *ptr;
break;
case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
case '+': case ',': case ';': case '=': /* sub-delims */
case '-': case '.': case '_': case '~': /* unreserved */
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
/* allowed */
state->buffer[state->offset++] = *ptr;
break;
default:
if (!(mb = parse_mb(state, PARSE_USERINFO, ptr, end, tmp, 0))) {
return FAILURE;
}
ptr += mb - 1;
}
} while(++ptr != end);
state->buffer[state->offset++] = 0;
return SUCCESS;
}
#if defined(PHP_WIN32) || defined(HAVE_UIDNA_IDNTOASCII)
typedef size_t (*parse_mb_func)(unsigned *wc, const char *ptr, const char *end);
static ZEND_RESULT_CODE to_utf16(parse_mb_func fn, const char *u8, uint16_t **u16, size_t *len)
{
size_t offset = 0, u8_len = strlen(u8);
*u16 = ecalloc(4 * sizeof(uint16_t), u8_len + 1);
*len = 0;
while (offset < u8_len) {
unsigned wc;
uint16_t buf[2], *ptr = buf;
size_t consumed = fn(&wc, &u8[offset], &u8[u8_len]);
if (!consumed) {
efree(*u16);
php_error_docref(NULL, E_WARNING, "Failed to parse UTF-8 at pos %zu of '%s'", offset, u8);
return FAILURE;
} else {
offset += consumed;
}
switch (wctoutf16(buf, wc)) {
case 2:
(*u16)[(*len)++] = *ptr++;
/* no break */
case 1:
(*u16)[(*len)++] = *ptr++;
break;
case 0:
default:
efree(*u16);
php_error_docref(NULL, E_WARNING, "Failed to convert UTF-32 'U+%X' to UTF-16", wc);
return FAILURE;
}
}
return SUCCESS;
}
#endif
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 256
#endif
#if PHP_HTTP_HAVE_IDN2
static ZEND_RESULT_CODE parse_idn2(struct parse_state *state, size_t prev_len)
{
char *idn = NULL;
int rv = -1;
if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
rv = idn2_lookup_u8((const unsigned char *) state->url.host, (unsigned char **) &idn, IDN2_NFC_INPUT);
}
# ifdef PHP_HTTP_HAVE_WCHAR
else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
rv = idn2_lookup_ul(state->url.host, &idn, 0);
}
# endif
if (rv != IDN2_OK) {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idn2_strerror(rv));
return FAILURE;
} else {
size_t idnlen = strlen(idn);
memcpy(state->url.host, idn, idnlen + 1);
free(idn);
state->offset += idnlen - prev_len;
return SUCCESS;
}
}
#elif PHP_HTTP_HAVE_IDN
static ZEND_RESULT_CODE parse_idn(struct parse_state *state, size_t prev_len)
{
char *idn = NULL;
int rv = -1;
if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
rv = idna_to_ascii_8z(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
}
# ifdef PHP_HTTP_HAVE_WCHAR
else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
rv = idna_to_ascii_lz(state->url.host, &idn, IDNA_ALLOW_UNASSIGNED|IDNA_USE_STD3_ASCII_RULES);
}
# endif
if (rv != IDNA_SUCCESS) {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN; %s", idna_strerror(rv));
return FAILURE;
} else {
size_t idnlen = strlen(idn);
memcpy(state->url.host, idn, idnlen + 1);
free(idn);
state->offset += idnlen - prev_len;
return SUCCESS;
}
}
#endif
#ifdef HAVE_UIDNA_IDNTOASCII
# if HAVE_UNICODE_UIDNA_H
# include
# else
typedef uint16_t UChar;
typedef enum { U_ZERO_ERROR = 0 } UErrorCode;
int32_t uidna_IDNToASCII(const UChar *src, int32_t srcLength, UChar *dest, int32_t destCapacity, int32_t options, void *parseError, UErrorCode *status);
# endif
static ZEND_RESULT_CODE parse_uidn(struct parse_state *state)
{
char *host_ptr;
uint16_t *uhost_str, ahost_str[MAXHOSTNAMELEN], *ahost_ptr;
size_t uhost_len, ahost_len;
UErrorCode error = U_ZERO_ERROR;
if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) {
return FAILURE;
}
#ifdef PHP_HTTP_HAVE_WCHAR
} else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) {
return FAILURE;
}
#endif
} else {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN; codepage not specified");
return FAILURE;
}
ahost_len = uidna_IDNToASCII(uhost_str, uhost_len, ahost_str, MAXHOSTNAMELEN, 3, NULL, &error);
efree(uhost_str);
if (error != U_ZERO_ERROR) {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN; ICU error %d", error);
return FAILURE;
}
host_ptr = state->url.host;
ahost_ptr = ahost_str;
PHP_HTTP_DUFF(ahost_len, *host_ptr++ = *ahost_ptr++);
*host_ptr = '\0';
state->offset += host_ptr - state->url.host;
return SUCCESS;
}
#endif
#if 0 && defined(PHP_WIN32)
static ZEND_RESULT_CODE parse_widn(struct parse_state *state)
{
char *host_ptr;
uint16_t *uhost_str, ahost_str[MAXHOSTNAMELEN], *ahost_ptr;
size_t uhost_len;
if (state->flags & PHP_HTTP_URL_PARSE_MBUTF8) {
if (SUCCESS != to_utf16(parse_mb_utf8, state->url.host, &uhost_str, &uhost_len)) {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
return FAILURE;
}
#ifdef PHP_HTTP_HAVE_WCHAR
} else if (state->flags & PHP_HTTP_URL_PARSE_MBLOC) {
if (SUCCESS != to_utf16(parse_mb_loc, state->url.host, &uhost_str, &uhost_len)) {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
return FAILURE;
}
#endif
} else {
php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
return FAILURE;
}
if (!IdnToAscii(IDN_ALLOW_UNASSIGNED|IDN_USE_STD3_ASCII_RULES, uhost_str, uhost_len, ahost_str, MAXHOSTNAMELEN)) {
efree(uhost_str);
php_error_docref(NULL, E_WARNING, "Failed to parse IDN");
return FAILURE;
}
efree(uhost_str);
host_ptr = state->url.host;
ahost_ptr = ahost_str;
PHP_HTTP_DUFF(wcslen(ahost_str), *host_ptr++ = *ahost_ptr++);
efree(ahost_str);
*host_ptr = '\0';
state->offset += host_ptr - state->url.host;
return SUCCESS;
}
#endif
#ifdef HAVE_INET_PTON
static const char *parse_ip6(struct parse_state *state, const char *ptr)
{
const char *error = NULL, *end = state->ptr, *tmp = memchr(ptr, ']', end - ptr);
if (tmp) {
size_t addrlen = tmp - ptr + 1;
char buf[16], *addr = estrndup(ptr + 1, addrlen - 2);
int rv = inet_pton(AF_INET6, addr, buf);
if (rv == 1) {
state->buffer[state->offset] = '[';
state->url.host = &state->buffer[state->offset];
inet_ntop(AF_INET6, buf, state->url.host + 1, state->maxlen - state->offset);
state->offset += strlen(state->url.host);
state->buffer[state->offset++] = ']';
state->buffer[state->offset++] = 0;
ptr = tmp + 1;
} else if (rv == -1) {
error = strerror(errno);
} else {
error = "unexpected '['";
}
efree(addr);
} else {
error = "expected ']'";
}
if (error) {
php_error_docref(NULL, E_WARNING, "Failed to parse hostinfo; %s", error);
return NULL;
}
return ptr;
}
#endif
static ZEND_RESULT_CODE parse_hostinfo(struct parse_state *state, const char *ptr)
{
size_t mb, len;
const char *end = state->ptr, *tmp = ptr, *port = NULL, *label = NULL;
#ifdef HAVE_INET_PTON
if (*ptr == '[' && !(ptr = parse_ip6(state, ptr))) {
return FAILURE;
}
#endif
if (ptr != end) do {
switch (*ptr) {
case ':':
if (port) {
php_error_docref(NULL, E_WARNING,
"Failed to parse port; unexpected ':' at pos %u in '%s'",
(unsigned) (ptr - tmp), tmp);
return FAILURE;
}
port = ptr + 1;
break;
case '%':
if (ptr[1] != '%' && (end - ptr <= 2 || !isxdigit(*(ptr+1)) || !isxdigit(*(ptr+2)))) {
php_error_docref(NULL, E_WARNING,
"Failed to parse hostinfo; invalid percent encoding at pos %u in '%s'",
(unsigned) (ptr - tmp), tmp);
return FAILURE;
}
state->buffer[state->offset++] = *ptr++;
state->buffer[state->offset++] = *ptr++;
state->buffer[state->offset++] = *ptr;
break;
case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
case '+': case ',': case ';': case '=': /* sub-delims */
case '-': case '.': case '_': case '~': /* unreserved */
if (port || !label) {
/* sort of a compromise, just ensure we don't end up
* with a dot at the beginning or two consecutive dots
*/
php_error_docref(NULL, E_WARNING,
"Failed to parse %s; unexpected '%c' at pos %u in '%s'",
port ? "port" : "host",
(unsigned char) *ptr, (unsigned) (ptr - tmp), tmp);
return FAILURE;
}
state->buffer[state->offset++] = *ptr;
label = NULL;
break;
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
if (port) {
php_error_docref(NULL, E_WARNING,
"Failed to parse port; unexpected char '%c' at pos %u in '%s'",
(unsigned char) *ptr, (unsigned) (ptr - tmp), tmp);
return FAILURE;
}
/* no break */
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
/* allowed */
if (port) {
state->url.port *= 10;
state->url.port += *ptr - '0';
} else {
label = ptr;
state->buffer[state->offset++] = *ptr;
}
break;
default:
if (ptr == end) {
break;
} else if (port) {
php_error_docref(NULL, E_WARNING,
"Failed to parse port; unexpected byte 0x%02x at pos %u in '%s'",
(unsigned char) *ptr, (unsigned) (ptr - tmp), tmp);
return FAILURE;
} else if (!(mb = parse_mb(state, PARSE_HOSTINFO, ptr, end, tmp, 0))) {
return FAILURE;
}
label = ptr;
ptr += mb - 1;
}
} while (++ptr != end);
if (!state->url.host) {
len = (port ? port - tmp - 1 : end - tmp);
state->url.host = &state->buffer[state->offset - len];
state->buffer[state->offset++] = 0;
}
if (state->flags & PHP_HTTP_URL_PARSE_TOIDN) {
#if PHP_HTTP_HAVE_IDN2
return parse_idn2(state, len);
#elif PHP_HTTP_HAVE_IDN
return parse_idn(state, len);
#endif
#ifdef HAVE_UIDNA_IDNTOASCII
return parse_uidn(state);
#endif
#if 0 && defined(PHP_WIN32)
return parse_widn(state);
#endif
}
return SUCCESS;
}
static const char *parse_authority(struct parse_state *state)
{
const char *tmp = state->ptr, *host = NULL;
do {
switch (*state->ptr) {
case '@':
/* userinfo delimiter */
if (host) {
php_error_docref(NULL, E_WARNING,
"Failed to parse userinfo; unexpected '@'");
return NULL;
}
host = state->ptr + 1;
if (tmp != state->ptr && SUCCESS != parse_userinfo(state, tmp)) {
return NULL;
}
tmp = state->ptr + 1;
break;
case '/':
case '?':
case '#':
case '\0':
EOD:
/* host delimiter */
if (tmp != state->ptr && SUCCESS != parse_hostinfo(state, tmp)) {
return NULL;
}
return state->ptr;
}
} while (++state->ptr <= state->end);
--state->ptr;
goto EOD;
}
static const char *parse_path(struct parse_state *state)
{
size_t mb;
const char *tmp;
/* is there actually a path to parse? */
if (!*state->ptr) {
return state->ptr;
}
tmp = state->ptr;
state->url.path = &state->buffer[state->offset];
do {
switch (*state->ptr) {
case '#':
case '?':
goto done;
case '%':
if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
php_error_docref(NULL, E_WARNING,
"Failed to parse path; invalid percent encoding at pos %u in '%s'",
(unsigned) (state->ptr - tmp), tmp);
return NULL;
}
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr;
break;
case '/': /* yeah, well */
case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
case '+': case ',': case ';': case '=': /* sub-delims */
case '-': case '.': case '_': case '~': /* unreserved */
case ':': case '@': /* pchar */
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
/* allowed */
state->buffer[state->offset++] = *state->ptr;
break;
default:
if (!(mb = parse_mb(state, PARSE_PATH, state->ptr, state->end, tmp, 0))) {
return NULL;
}
state->ptr += mb - 1;
}
} while (++state->ptr < state->end);
done:
/* did we have any path component ? */
if (tmp != state->ptr) {
state->buffer[state->offset++] = 0;
} else {
state->url.path = NULL;
}
return state->ptr;
}
static const char *parse_query(struct parse_state *state)
{
size_t mb;
const char *tmp = state->ptr + !!*state->ptr;
/* is there actually a query to parse? */
if (*state->ptr != '?') {
return state->ptr;
}
/* skip initial '?' */
tmp = ++state->ptr;
state->url.query = &state->buffer[state->offset];
while (state->ptr < state->end) {
switch (*state->ptr) {
case '#':
goto done;
case '%':
if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
php_error_docref(NULL, E_WARNING,
"Failed to parse query; invalid percent encoding at pos %u in '%s'",
(unsigned) (state->ptr - tmp), tmp);
return NULL;
}
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr;
break;
/* RFC1738 unsafe */
case '{': case '}':
case '<': case '>':
case '[': case ']':
case '|': case '\\': case '^': case '`': case '"': case ' ':
if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) {
state->buffer[state->offset++] = '%';
state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4];
state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) & 0xf];
break;
}
/* no break */
case '?': case '/': /* yeah, well */
case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
case '+': case ',': case ';': case '=': /* sub-delims */
case '-': case '.': case '_': case '~': /* unreserved */
case ':': case '@': /* pchar */
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
/* allowed */
state->buffer[state->offset++] = *state->ptr;
break;
default:
if (!(mb = parse_mb(state, PARSE_QUERY, state->ptr, state->end, tmp, 0))) {
return NULL;
}
state->ptr += mb - 1;
}
++state->ptr;
}
done:
state->buffer[state->offset++] = 0;
return state->ptr;
}
static const char *parse_fragment(struct parse_state *state)
{
size_t mb;
const char *tmp;
/* is there actually a fragment to parse? */
if (*state->ptr != '#') {
return state->ptr;
}
/* skip initial '#' */
tmp = ++state->ptr;
state->url.fragment = &state->buffer[state->offset];
do {
switch (*state->ptr) {
case '%':
if (state->ptr[1] != '%' && (state->end - state->ptr <= 2 || !isxdigit(*(state->ptr+1)) || !isxdigit(*(state->ptr+2)))) {
php_error_docref(NULL, E_WARNING,
"Failed to parse fragment; invalid percent encoding at pos %u in '%s'",
(unsigned) (state->ptr - tmp), tmp);
return NULL;
}
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr++;
state->buffer[state->offset++] = *state->ptr;
break;
/* RFC1738 unsafe */
case '{': case '}':
case '<': case '>':
case '[': case ']':
case '|': case '\\': case '^': case '`': case '"': case ' ':
if (state->flags & PHP_HTTP_URL_PARSE_TOPCT) {
state->buffer[state->offset++] = '%';
state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) >> 4];
state->buffer[state->offset++] = parse_xdigits[((unsigned char) *state->ptr) & 0xf];
break;
}
/* no break */
case '?': case '/':
case '!': case '$': case '&': case '\'': case '(': case ')': case '*':
case '+': case ',': case ';': case '=': /* sub-delims */
case '-': case '.': case '_': case '~': /* unreserved */
case ':': case '@': /* pchar */
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
/* allowed */
state->buffer[state->offset++] = *state->ptr;
break;
default:
if (!(mb = parse_mb(state, PARSE_FRAGMENT, state->ptr, state->end, tmp, 0))) {
return NULL;
}
state->ptr += mb - 1;
}
} while (++state->ptr < state->end);
state->buffer[state->offset++] = 0;
return state->ptr;
}
static const char *parse_hier(struct parse_state *state)
{
if (*state->ptr == '/') {
if (state->end - state->ptr > 1) {
if (*(state->ptr + 1) == '/') {
state->ptr += 2;
if (!(state->ptr = parse_authority(state))) {
return NULL;
}
}
}
}
return parse_path(state);
}
static const char *parse_scheme(struct parse_state *state)
{
size_t mb;
const char *tmp = state->ptr;
do {
switch (*state->ptr) {
case ':':
/* scheme delimiter */
state->url.scheme = &state->buffer[0];
state->buffer[state->offset++] = 0;
return ++state->ptr;
case '0': case '1': case '2': case '3': case '4': case '5': case '6':
case '7': case '8': case '9':
case '+': case '-': case '.':
if (state->ptr == tmp) {
goto softfail;
}
/* no break */
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
case 'V': case 'W': case 'X': case 'Y': case 'Z':
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
/* scheme part */
state->buffer[state->offset++] = *state->ptr;
break;
default:
if (!(mb = parse_mb(state, PARSE_SCHEME, state->ptr, state->end, tmp, 1))) {
goto softfail;
}
state->ptr += mb - 1;
}
} while (++state->ptr != state->end);
softfail:
state->offset = 0;
return state->ptr = tmp;
}
php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags)
{
size_t maxlen = 3 * len + 8 /* null bytes for all components */;
struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen);
state->end = str + len;
state->ptr = str;
state->flags = flags;
state->maxlen = maxlen;
if (!parse_scheme(state)) {
php_error_docref(NULL, E_WARNING, "Failed to parse URL scheme: '%s'", state->ptr);
efree(state);
return NULL;
}
if (!parse_hier(state)) {
efree(state);
return NULL;
}
if (!parse_query(state)) {
php_error_docref(NULL, E_WARNING, "Failed to parse URL query: '%s'", state->ptr);
efree(state);
return NULL;
}
if (!parse_fragment(state)) {
php_error_docref(NULL, E_WARNING, "Failed to parse URL fragment: '%s'", state->ptr);
efree(state);
return NULL;
}
return (php_http_url_t *) state;
}
php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags)
{
size_t maxlen = 3 * len;
struct parse_state *state = ecalloc(1, sizeof(*state) + maxlen);
state->end = str + len;
state->ptr = str;
state->flags = flags;
state->maxlen = maxlen;
if (!(state->ptr = parse_authority(state))) {
efree(state);
return NULL;
}
if (state->ptr != state->end) {
php_error_docref(NULL, E_WARNING,
"Failed to parse URL authority, unexpected character at pos %u in '%s'",
(unsigned) (state->ptr - str), str);
efree(state);
return NULL;
}
return (php_http_url_t *) state;
}
static zend_class_entry *php_http_url_class_entry;
static zend_class_entry *php_http_env_url_class_entry;
zend_class_entry *php_http_url_get_class_entry(void)
{
return php_http_url_class_entry;
}
zend_class_entry *php_http_get_env_url_class_entry(void)
{
return php_http_env_url_class_entry;
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl___construct, 0, 0, 0)
ZEND_ARG_INFO(0, old_url)
ZEND_ARG_INFO(0, new_url)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpUrl, __construct)
{
zval *new_url = NULL, *old_url = NULL;
zend_long flags = 0;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "|z!z!l", &old_url, &new_url, &flags), invalid_arg, return);
/* always set http\Url::FROM_ENV for instances of http\Env\Url */
if (instanceof_function(Z_OBJCE_P(getThis()), php_http_env_url_class_entry)) {
flags |= PHP_HTTP_URL_FROM_ENV;
}
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
{
php_http_url_t *res_purl, *new_purl = NULL, *old_purl = NULL;
if (new_url) {
new_purl = php_http_url_from_zval(new_url, flags);
if (!new_purl) {
zend_restore_error_handling(&zeh);
return;
}
}
if (old_url) {
old_purl = php_http_url_from_zval(old_url, flags);
if (!old_purl) {
if (new_purl) {
php_http_url_free(&new_purl);
}
zend_restore_error_handling(&zeh);
return;
}
}
res_purl = php_http_url_mod(old_purl, new_purl, flags);
php_http_url_to_struct(res_purl, getThis());
php_http_url_free(&res_purl);
if (old_purl) {
php_http_url_free(&old_purl);
}
if (new_purl) {
php_http_url_free(&new_purl);
}
}
zend_restore_error_handling(&zeh);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_mod, 0, 0, 1)
ZEND_ARG_INFO(0, more_url_parts)
ZEND_ARG_INFO(0, flags)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpUrl, mod)
{
zval *new_url = NULL;
zend_long flags = PHP_HTTP_URL_JOIN_PATH | PHP_HTTP_URL_JOIN_QUERY | PHP_HTTP_URL_SANITIZE_PATH;
zend_error_handling zeh;
php_http_expect(SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS(), "z!|l", &new_url, &flags), invalid_arg, return);
zend_replace_error_handling(EH_THROW, php_http_get_exception_bad_url_class_entry(), &zeh);
{
php_http_url_t *new_purl = NULL, *old_purl = NULL;
if (new_url) {
new_purl = php_http_url_from_zval(new_url, flags);
if (!new_purl) {
zend_restore_error_handling(&zeh);
return;
}
}
if ((old_purl = php_http_url_from_struct(HASH_OF(getThis())))) {
php_http_url_t *res_purl;
ZVAL_OBJ(return_value, zend_objects_clone_obj(getThis()));
res_purl = php_http_url_mod(old_purl, new_purl, flags);
php_http_url_to_struct(res_purl, return_value);
php_http_url_free(&res_purl);
php_http_url_free(&old_purl);
}
if (new_purl) {
php_http_url_free(&new_purl);
}
}
zend_restore_error_handling(&zeh);
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toString, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpUrl, toString)
{
if (SUCCESS == zend_parse_parameters_none()) {
php_http_url_t *purl;
if ((purl = php_http_url_from_struct(HASH_OF(getThis())))) {
char *str;
size_t len;
php_http_url_to_string(purl, &str, &len, 0);
php_http_url_free(&purl);
RETURN_STR(php_http_cs2zs(str, len));
}
}
RETURN_EMPTY_STRING();
}
ZEND_BEGIN_ARG_INFO_EX(ai_HttpUrl_toArray, 0, 0, 0)
ZEND_END_ARG_INFO();
PHP_METHOD(HttpUrl, toArray)
{
php_http_url_t *purl;
if (SUCCESS != zend_parse_parameters_none()) {
return;
}
/* strip any non-URL properties */
purl = php_http_url_from_struct(HASH_OF(getThis()));
php_http_url_to_struct(purl, return_value);
php_http_url_free(&purl);
}
static zend_function_entry php_http_url_methods[] = {
PHP_ME(HttpUrl, __construct, ai_HttpUrl___construct, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
PHP_ME(HttpUrl, mod, ai_HttpUrl_mod, ZEND_ACC_PUBLIC)
PHP_ME(HttpUrl, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC)
ZEND_MALIAS(HttpUrl, __toString, toString, ai_HttpUrl_toString, ZEND_ACC_PUBLIC)
PHP_ME(HttpUrl, toArray, ai_HttpUrl_toArray, ZEND_ACC_PUBLIC)
EMPTY_FUNCTION_ENTRY
};
PHP_MINIT_FUNCTION(http_url)
{
zend_class_entry ce = {0};
INIT_NS_CLASS_ENTRY(ce, "http", "Url", php_http_url_methods);
php_http_url_class_entry = zend_register_internal_class(&ce);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("scheme"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("user"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("pass"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("host"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("port"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("path"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("query"), ZEND_ACC_PUBLIC);
zend_declare_property_null(php_http_url_class_entry, ZEND_STRL("fragment"), ZEND_ACC_PUBLIC);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("REPLACE"), PHP_HTTP_URL_REPLACE);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_PATH"), PHP_HTTP_URL_JOIN_PATH);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("JOIN_QUERY"), PHP_HTTP_URL_JOIN_QUERY);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_USER"), PHP_HTTP_URL_STRIP_USER);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PASS"), PHP_HTTP_URL_STRIP_PASS);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_AUTH"), PHP_HTTP_URL_STRIP_AUTH);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PORT"), PHP_HTTP_URL_STRIP_PORT);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_PATH"), PHP_HTTP_URL_STRIP_PATH);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_QUERY"), PHP_HTTP_URL_STRIP_QUERY);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_FRAGMENT"), PHP_HTTP_URL_STRIP_FRAGMENT);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("STRIP_ALL"), PHP_HTTP_URL_STRIP_ALL);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("FROM_ENV"), PHP_HTTP_URL_FROM_ENV);
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("SANITIZE_PATH"), PHP_HTTP_URL_SANITIZE_PATH);
#ifdef PHP_HTTP_HAVE_WCHAR
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBLOC"), PHP_HTTP_URL_PARSE_MBLOC);
#endif
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_MBUTF8"), PHP_HTTP_URL_PARSE_MBUTF8);
#if defined(PHP_HTTP_HAVE_IDN2) || defined(PHP_HTTP_HAVE_IDN) || defined(HAVE_UIDNA_IDNTOASCII)
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOIDN"), PHP_HTTP_URL_PARSE_TOIDN);
#endif
zend_declare_class_constant_long(php_http_url_class_entry, ZEND_STRL("PARSE_TOPCT"), PHP_HTTP_URL_PARSE_TOPCT);
INIT_NS_CLASS_ENTRY(ce, "http\\Env", "Url", php_http_url_methods);
php_http_env_url_class_entry = zend_register_internal_class_ex(&ce, php_http_url_class_entry);
return SUCCESS;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_url.h 0000644 0001750 0000144 00000010332 12667772426 016033 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_URL_H
#define PHP_HTTP_URL_H
#include
/* php_http_url_mod() */
#define PHP_HTTP_URL_REPLACE 0x000
#define PHP_HTTP_URL_JOIN_PATH 0x001
#define PHP_HTTP_URL_JOIN_QUERY 0x002
#define PHP_HTTP_URL_STRIP_USER 0x004
#define PHP_HTTP_URL_STRIP_PASS 0x008
#define PHP_HTTP_URL_STRIP_AUTH (PHP_HTTP_URL_STRIP_USER|PHP_HTTP_URL_STRIP_PASS)
#define PHP_HTTP_URL_STRIP_PORT 0x020
#define PHP_HTTP_URL_STRIP_PATH 0x040
#define PHP_HTTP_URL_STRIP_QUERY 0x080
#define PHP_HTTP_URL_STRIP_FRAGMENT 0x100
#define PHP_HTTP_URL_STRIP_ALL ( \
PHP_HTTP_URL_STRIP_AUTH | \
PHP_HTTP_URL_STRIP_PORT | \
PHP_HTTP_URL_STRIP_PATH | \
PHP_HTTP_URL_STRIP_QUERY | \
PHP_HTTP_URL_STRIP_FRAGMENT \
)
#define PHP_HTTP_URL_FROM_ENV 0x1000
#define PHP_HTTP_URL_SANITIZE_PATH 0x2000
/* parse multibyte according to locale */
#define PHP_HTTP_URL_PARSE_MBLOC 0x10000
/* parse utf8 multibyte sequences */
#define PHP_HTTP_URL_PARSE_MBUTF8 0x20000
/* convert multibyte hostnames to IDNA */
#define PHP_HTTP_URL_PARSE_TOIDN 0x100000
/* percent encode multibyte sequences in userinfo, path, query and fragment */
#define PHP_HTTP_URL_PARSE_TOPCT 0x200000
typedef struct php_http_url {
/* compatible to php_url, but do not use php_url_free() */
char *scheme;
char *user;
char *pass;
char *host;
unsigned short port;
char *path;
char *query;
char *fragment;
} php_http_url_t;
PHP_HTTP_API php_http_url_t *php_http_url_parse(const char *str, size_t len, unsigned flags);
PHP_HTTP_API php_http_url_t *php_http_url_parse_authority(const char *str, size_t len, unsigned flags);
PHP_HTTP_API php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags);
PHP_HTTP_API php_http_url_t *php_http_url_copy(const php_http_url_t *url, zend_bool persistent);
PHP_HTTP_API php_http_url_t *php_http_url_from_struct(HashTable *ht);
PHP_HTTP_API php_http_url_t *php_http_url_from_zval(zval *value, unsigned flags);
PHP_HTTP_API HashTable *php_http_url_to_struct(const php_http_url_t *url, zval *strct);
PHP_HTTP_API char *php_http_url_to_string(const php_http_url_t *url, char **url_str, size_t *url_len, zend_bool persistent);
PHP_HTTP_API char *php_http_url_authority_to_string(const php_http_url_t *url, char **url_str, size_t *url_len);
PHP_HTTP_API void php_http_url_free(php_http_url_t **url);
PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash(HashTable *hash, const char *pre_encoded_str, size_t pre_encoded_len, char **encoded_str, size_t *encoded_len);
PHP_HTTP_API ZEND_RESULT_CODE php_http_url_encode_hash_ex(HashTable *hash, php_http_buffer_t *qstr, const char *arg_sep_str, size_t arg_sep_len, const char *val_sep_str, size_t val_sep_len, const char *pre_encoded_str, size_t pre_encoded_len);
static inline void php_http_url_argsep(const char **str, size_t *len)
{
if (SUCCESS != php_http_ini_entry(ZEND_STRL("arg_separator.output"), str, len, 0) || !*len) {
*str = PHP_HTTP_URL_ARGSEP;
*len = lenof(PHP_HTTP_URL_ARGSEP);
}
}
static inline zend_bool php_http_url_is_empty(const php_http_url_t *url) {
return !(url->scheme || url->pass || url->user || url->host || url->port || url->path || url->query || url->fragment);
}
PHP_HTTP_API zend_class_entry *php_http_url_get_class_entry(void);
PHP_HTTP_API zend_class_entry *php_http_get_env_url_class_entry(void);
PHP_MINIT_FUNCTION(http_url);
#define php_http_url_object_new php_http_object_new
#define php_http_url_object_new_ex php_http_object_new_ex
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_utf8.h 0000644 0001750 0000144 00000044637 12667772426 016136 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_UTF8_H
#define PHP_HTTP_UTF8_H
typedef struct utf8_range {
unsigned int start;
unsigned int end;
unsigned char step;
} utf8_range_t;
static const unsigned char utf8_mblen[256] = {
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6
};
static const unsigned char utf8_mask[] = {
0, 0x7f, 0x1f, 0x0f, 0x07, 0x03, 0x01
};
static const utf8_range_t utf8_ranges[] = {
/* BEGIN::UTF8TABLE */
{ 0x0041, 0x005A, 1},
{ 0x0061, 0x007A, 1},
{ 0x00AA, 0, 0},
{ 0x00B5, 0, 0},
{ 0x00BA, 0, 0},
{ 0x00C0, 0x00D6, 1},
{ 0x00D8, 0x00F6, 1},
{ 0x00F8, 0x00FF, 1},
{ 0x0100, 0x017F, 1},
{ 0x0180, 0x024F, 1},
{ 0x0250, 0x02AF, 1},
{ 0x02B0, 0x02C1, 1},
{ 0x02C6, 0x02D1, 1},
{ 0x02E0, 0x02E4, 1},
{ 0x02EE, 0, 0},
{ 0x0345, 0, 0},
{ 0x0370, 0x0373, 1},
{ 0x0376, 0x0377, 1},
{ 0x037A, 0x037D, 1},
{ 0x0386, 0, 0},
{ 0x0388, 0x038A, 1},
{ 0x038C, 0, 0},
{ 0x038E, 0x03A1, 1},
{ 0x03A3, 0x03CE, 1},
{ 0x03D0, 0x03F5, 1},
{ 0x03F7, 0x03FF, 1},
{ 0x0400, 0x0481, 1},
{ 0x048A, 0x04FF, 1},
{ 0x0500, 0x0523, 1},
{ 0x0531, 0x0556, 1},
{ 0x0559, 0, 0},
{ 0x0561, 0x0587, 1},
{ 0x05D0, 0x05EA, 1},
{ 0x05F0, 0x05F2, 1},
{ 0x0621, 0x064A, 1},
{ 0x066E, 0x066F, 1},
{ 0x0671, 0x06D3, 1},
{ 0x06D5, 0, 0},
{ 0x06E5, 0x06E6, 1},
{ 0x06EE, 0x06EF, 1},
{ 0x06FA, 0x06FC, 1},
{ 0x06FF, 0, 0},
{ 0x0710, 0, 0},
{ 0x0712, 0x072F, 1},
{ 0x074D, 0x074F, 1},
{ 0x0750, 0x077F, 1},
{ 0x0780, 0x07A5, 1},
{ 0x07B1, 0, 0},
{ 0x07C0, 0x07EA, 1},
{ 0x07F4, 0x07F5, 1},
{ 0x07FA, 0, 0},
{ 0x0901, 0x0939, 1},
{ 0x093C, 0x094D, 1},
{ 0x0950, 0x0954, 1},
{ 0x0958, 0x0961, 1},
{ 0x0962, 0, 0},
{ 0x0963, 0, 0},
{ 0x0972, 0, 0},
{ 0x097B, 0x097F, 1},
{ 0x0981, 0x0983, 1},
{ 0x0985, 0x098C, 1},
{ 0x098F, 0, 0},
{ 0x0990, 0, 0},
{ 0x0993, 0x09A8, 1},
{ 0x09AA, 0x09B0, 1},
{ 0x09B2, 0, 0},
{ 0x09B6, 0x09B9, 1},
{ 0x09BC, 0x09C4, 1},
{ 0x09C7, 0, 0},
{ 0x09C8, 0, 0},
{ 0x09CB, 0x09CE, 1},
{ 0x09D7, 0, 0},
{ 0x09DC, 0, 0},
{ 0x09DD, 0, 0},
{ 0x09DF, 0x09E3, 1},
{ 0x09F0, 0x09FA, 1},
{ 0x0A01, 0x0A03, 1},
{ 0x0A05, 0x0A0A, 1},
{ 0x0A0F, 0, 0},
{ 0x0A10, 0, 0},
{ 0x0A13, 0x0A28, 1},
{ 0x0A2A, 0x0A30, 1},
{ 0x0A32, 0, 0},
{ 0x0A33, 0, 0},
{ 0x0A35, 0, 0},
{ 0x0A36, 0, 0},
{ 0x0A38, 0, 0},
{ 0x0A39, 0, 0},
{ 0x0A3C, 0, 0},
{ 0x0A3E, 0x0A42, 1},
{ 0x0A47, 0, 0},
{ 0x0A48, 0, 0},
{ 0x0A4B, 0x0A4D, 1},
{ 0x0A51, 0, 0},
{ 0x0A59, 0x0A5C, 1},
{ 0x0A5E, 0, 0},
{ 0x0A70, 0x0A75, 1},
{ 0x0A81, 0x0A83, 1},
{ 0x0A85, 0x0A8D, 1},
{ 0x0A8F, 0x0A91, 1},
{ 0x0A93, 0x0AA8, 1},
{ 0x0AAA, 0x0AB0, 1},
{ 0x0AB2, 0, 0},
{ 0x0AB3, 0, 0},
{ 0x0AB5, 0x0AB9, 1},
{ 0x0ABC, 0x0AC5, 1},
{ 0x0AC7, 0x0AC9, 1},
{ 0x0ACB, 0x0ACD, 1},
{ 0x0AD0, 0, 0},
{ 0x0AE0, 0x0AE3, 1},
{ 0x0AF1, 0, 0},
{ 0x0B01, 0x0B03, 1},
{ 0x0B05, 0x0B0C, 1},
{ 0x0B0F, 0, 0},
{ 0x0B10, 0, 0},
{ 0x0B13, 0x0B28, 1},
{ 0x0B2A, 0x0B30, 1},
{ 0x0B32, 0, 0},
{ 0x0B33, 0, 0},
{ 0x0B35, 0x0B39, 1},
{ 0x0B3C, 0x0B44, 1},
{ 0x0B47, 0x0B48, 1},
{ 0x0B4B, 0x0B4D, 1},
{ 0x0B56, 0x0B57, 1},
{ 0x0B5C, 0, 0},
{ 0x0B5D, 0, 0},
{ 0x0B5F, 0x0B63, 1},
{ 0x0B70, 0, 0},
{ 0x0B71, 0, 0},
{ 0x0B82, 0, 0},
{ 0x0B83, 0, 0},
{ 0x0B85, 0x0B8A, 1},
{ 0x0B8E, 0x0B90, 1},
{ 0x0B92, 0x0B95, 1},
{ 0x0B99, 0, 0},
{ 0x0B9A, 0, 0},
{ 0x0B9C, 0, 0},
{ 0x0B9E, 0, 0},
{ 0x0B9F, 0, 0},
{ 0x0BA3, 0, 0},
{ 0x0BA4, 0, 0},
{ 0x0BA8, 0x0BAA, 1},
{ 0x0BAE, 0x0BB9, 1},
{ 0x0BBE, 0x0BC2, 1},
{ 0x0BC6, 0x0BC8, 1},
{ 0x0BCA, 0x0BCD, 1},
{ 0x0BD0, 0, 0},
{ 0x0BD7, 0, 0},
{ 0x0BF0, 0x0BFA, 1},
{ 0x0C01, 0x0C03, 1},
{ 0x0C05, 0x0C0C, 1},
{ 0x0C0E, 0x0C10, 1},
{ 0x0C12, 0x0C28, 1},
{ 0x0C2A, 0x0C33, 1},
{ 0x0C35, 0x0C39, 1},
{ 0x0C3D, 0x0C44, 1},
{ 0x0C46, 0x0C48, 1},
{ 0x0C4A, 0x0C4D, 1},
{ 0x0C55, 0x0C56, 1},
{ 0x0C58, 0x0C59, 1},
{ 0x0C60, 0x0C63, 1},
{ 0x0C82, 0x0C83, 1},
{ 0x0C85, 0x0C8C, 1},
{ 0x0C8E, 0x0C90, 1},
{ 0x0C92, 0x0CA8, 1},
{ 0x0CAA, 0x0CB3, 1},
{ 0x0CB5, 0x0CB9, 1},
{ 0x0CBC, 0x0CC4, 1},
{ 0x0CC6, 0x0CC8, 1},
{ 0x0CCA, 0x0CCD, 1},
{ 0x0CD5, 0x0CD6, 1},
{ 0x0CDE, 0, 0},
{ 0x0CE0, 0x0CE3, 1},
{ 0x0CF1, 0, 0},
{ 0x0CF2, 0, 0},
{ 0x0D02, 0x0D03, 1},
{ 0x0D05, 0x0D0C, 1},
{ 0x0D0E, 0x0D10, 1},
{ 0x0D12, 0x0D28, 1},
{ 0x0D2A, 0x0D39, 1},
{ 0x0D3D, 0x0D44, 1},
{ 0x0D46, 0x0D48, 1},
{ 0x0D4A, 0x0D4D, 1},
{ 0x0D57, 0, 0},
{ 0x0D60, 0x0D63, 1},
{ 0x0D79, 0x0D7F, 1},
{ 0x0D82, 0x0D83, 1},
{ 0x0D85, 0x0D96, 1},
{ 0x0D9A, 0x0DB1, 1},
{ 0x0DB3, 0x0DBB, 1},
{ 0x0DBD, 0, 0},
{ 0x0DC0, 0x0DC6, 1},
{ 0x0DCA, 0, 0},
{ 0x0DCF, 0x0DD4, 1},
{ 0x0DD6, 0, 0},
{ 0x0DD8, 0x0DDF, 1},
{ 0x0DF2, 0x0DF4, 1},
{ 0x0E01, 0x0E2E, 1},
{ 0x0E30, 0x0E3A, 1},
{ 0x0E40, 0x0E45, 1},
{ 0x0E47, 0x0E4E, 1},
{ 0x0E81, 0x0E82, 1},
{ 0x0E84, 0, 0},
{ 0x0E87, 0x0E88, 1},
{ 0x0E8A, 0, 0},
{ 0x0E8D, 0, 0},
{ 0x0E94, 0x0E97, 1},
{ 0x0E99, 0x0E9F, 1},
{ 0x0EA1, 0x0EA3, 1},
{ 0x0EA5, 0, 0},
{ 0x0EA7, 0, 0},
{ 0x0EAA, 0x0EAB, 1},
{ 0x0EAD, 0x0EB0, 1},
{ 0x0EB2, 0x0EB3, 1},
{ 0x0EBD, 0, 0},
{ 0x0EC0, 0x0EC4, 1},
{ 0x0EC6, 0, 0},
{ 0x0EDC, 0x0EDD, 1},
{ 0x0F00, 0, 0},
{ 0x0F40, 0x0F47, 1},
{ 0x0F49, 0x0F6C, 1},
{ 0x0F88, 0x0F8B, 1},
{ 0x1000, 0x102A, 1},
{ 0x1050, 0x1055, 1},
{ 0x105A, 0x105D, 1},
{ 0x1061, 0, 0},
{ 0x0165, 0, 0},
{ 0x1066, 0, 0},
{ 0x106E, 0x1070, 1},
{ 0x1075, 0x1081, 1},
{ 0x108E, 0, 0},
{ 0x10A0, 0x10C5, 1},
{ 0x10D0, 0x10FA, 1},
{ 0x10FC, 0, 0},
{ 0x1100, 0x1159, 1},
{ 0x115F, 0x11A2, 1},
{ 0x11A8, 0x11F9, 1},
{ 0x1200, 0x1248, 1},
{ 0x124A, 0x124D, 1},
{ 0x1250, 0x1256, 1},
{ 0x1258, 0, 0},
{ 0x125A, 0x125D, 1},
{ 0x1260, 0x1288, 1},
{ 0x128A, 0x128D, 1},
{ 0x1290, 0x12B0, 1},
{ 0x12B2, 0x12B5, 1},
{ 0x12B8, 0x12BE, 1},
{ 0x12C0, 0, 0},
{ 0x12C2, 0x12C5, 1},
{ 0x12C8, 0x12D6, 1},
{ 0x12D8, 0x1310, 1},
{ 0x1312, 0x1315, 1},
{ 0x1318, 0x135A, 1},
{ 0x1380, 0x138F, 1},
{ 0x13A0, 0x13F4, 1},
{ 0x1401, 0x166C, 1},
{ 0x166F, 0x1676, 1},
{ 0x1681, 0x169A, 1},
{ 0x16A0, 0x16EA, 1},
{ 0x16EE, 0x16F0, 1},
{ 0x1700, 0x170C, 1},
{ 0x170E, 0x1711, 1},
{ 0x1720, 0x1731, 1},
{ 0x1740, 0x1751, 1},
{ 0x1760, 0x176C, 1},
{ 0x176E, 0x1770, 1},
{ 0x1780, 0x17B3, 1},
{ 0x17D7, 0, 0},
{ 0x17DC, 0, 0},
{ 0x1820, 0x1877, 1},
{ 0x1880, 0x18A8, 1},
{ 0x18AA, 0, 0},
{ 0x1900, 0x191C, 1},
{ 0x1946, 0x194F, 1},
{ 0x1950, 0x196D, 1},
{ 0x1970, 0x1974, 1},
{ 0x1980, 0x19A9, 1},
{ 0x19C1, 0x19C7, 1},
{ 0x19D0, 0x19D9, 1},
{ 0x1A00, 0x1A16, 1},
{ 0x1B05, 0x1B33, 1},
{ 0x1B45, 0x1B4B, 1},
{ 0x1B50, 0x1B59, 1},
{ 0x1B83, 0x1BA0, 1},
{ 0x1BAE, 0x1BAF, 1},
{ 0x1C00, 0x1C23, 1},
{ 0x1C4D, 0x1C4F, 1},
{ 0x1C5A, 0x1C7D, 1},
{ 0x1D00, 0x1DBF, 1},
{ 0x1E00, 0x1E9F, 1},
{ 0x1EA0, 0x1EFF, 1},
{ 0x1F00, 0x1F15, 1},
{ 0x1F18, 0x1F1D, 1},
{ 0x1F20, 0x1F45, 1},
{ 0x1F48, 0x1F4D, 1},
{ 0x1F50, 0x1F57, 1},
{ 0x1F59, 0, 0},
{ 0x1F5B, 0, 0},
{ 0x1F5D, 0, 0},
{ 0x1F5F, 0x1F7D, 1},
{ 0x1F80, 0x1FB4, 1},
{ 0x1FB6, 0x1FBC, 1},
{ 0x1FBE, 0, 0},
{ 0x1FC2, 0x1FC4, 1},
{ 0x1FC6, 0x1FCC, 1},
{ 0x1FD0, 0x1FD3, 1},
{ 0x1FD6, 0x1FDB, 1},
{ 0x1FE0, 0x1FEC, 1},
{ 0x1FF2, 0x1FF4, 1},
{ 0x1FF6, 0x1FFC, 1},
{ 0x2071, 0, 0},
{ 0x207F, 0, 0},
{ 0x2090, 0x2094, 1},
{ 0x2102, 0, 0},
{ 0x2107, 0, 0},
{ 0x210A, 0x2113, 1},
{ 0x2115, 0, 0},
{ 0x2119, 0x211D, 1},
{ 0x2124, 0, 0},
{ 0x2126, 0, 0},
{ 0x2128, 0x212D, 1},
{ 0x212F, 0x2139, 1},
{ 0x213C, 0x213F, 1},
{ 0x2145, 0x2149, 1},
{ 0x214E, 0, 0},
{ 0x2160, 0x2188, 1},
{ 0x249C, 0x24E9, 1},
{ 0x2C00, 0x2C2E, 1},
{ 0x2C30, 0x2C5E, 1},
{ 0x2C60, 0x2C6F, 1},
{ 0x2C71, 0x2C7D, 1},
{ 0x2C80, 0x2CE4, 1},
{ 0x2D00, 0x2D25, 1},
{ 0x2D30, 0x2D65, 1},
{ 0x2D6F, 0, 0},
{ 0x2D80, 0x2D96, 1},
{ 0x2DA0, 0x2DA6, 1},
{ 0x2DA8, 0x2DAE, 1},
{ 0x2DB0, 0x2DB6, 1},
{ 0x2DB8, 0x2DBE, 1},
{ 0x2DC0, 0x2DC6, 1},
{ 0x2DC8, 0x2DCE, 1},
{ 0x2DD0, 0x2DD6, 1},
{ 0x2DD8, 0x2DDE, 1},
{ 0x3005, 0x3007, 1},
{ 0x3021, 0x3029, 1},
{ 0x3031, 0x3035, 1},
{ 0x3038, 0x303C, 1},
{ 0x3041, 0x3096, 1},
{ 0x309D, 0x309F, 1},
{ 0x30A1, 0x30FA, 1},
{ 0x30FC, 0x30FF, 1},
{ 0x3105, 0x312D, 1},
{ 0x3131, 0x318E, 1},
{ 0x31A0, 0x31B7, 1},
{ 0x31F0, 0x31FF, 1},
{ 0x3400, 0x4DB5, 1},
{ 0x4E00, 0x9FBB, 1},
{ 0xA000, 0xA48C, 1},
{ 0xA500, 0xA60B, 1},
{ 0xA610, 0xA61F, 1},
{ 0xA62A, 0xA62B, 1},
{ 0xA640, 0xA65F, 1},
{ 0xA662, 0xA66E, 1},
{ 0xA680, 0xA697, 1},
{ 0xA717, 0xA71F, 1},
{ 0xA722, 0xA78C, 1},
{ 0xA7FB, 0xA7FF, 1},
{ 0xA800, 0, 0},
{ 0xA801, 0, 0},
{ 0xA803, 0xA805, 1},
{ 0xA807, 0xA80A, 1},
{ 0xA80C, 0xA822, 1},
{ 0xA840, 0xA873, 1},
{ 0xA882, 0xA8B3, 1},
{ 0xA90A, 0xA92D, 1},
{ 0xA930, 0xA946, 1},
{ 0xAA00, 0xAA28, 1},
{ 0xAA40, 0xAA42, 1},
{ 0xAA44, 0xAA4B, 1},
{ 0xAC00, 0xD7A3, 1},
{ 0xF900, 0xFA2D, 1},
{ 0xFA30, 0xFA6A, 1},
{ 0xFA70, 0xFAD9, 1},
{ 0xFB00, 0xFB06, 1},
{ 0xFB13, 0xFB17, 1},
{ 0xFB1D, 0, 0},
{ 0xFB1F, 0xFB28, 1},
{ 0xFB2A, 0xFB36, 1},
{ 0xFB38, 0xFB3C, 1},
{ 0xFB3E, 0, 0},
{ 0xFB40, 0, 0},
{ 0xFB41, 0, 0},
{ 0xFB43, 0, 0},
{ 0xFB44, 0, 0},
{ 0xFB46, 0xFB4F, 1},
{ 0xFB50, 0xFBB1, 1},
{ 0xFBD3, 0xFD3D, 1},
{ 0xFD50, 0xFD8F, 1},
{ 0xFD92, 0xFDC7, 1},
{ 0xFDF0, 0xFDFB, 1},
{ 0xFE70, 0xFE74, 1},
{ 0xFE76, 0xFEFC, 1},
{ 0xFF21, 0xFF3A, 1},
{ 0xFF41, 0xFF5A, 1},
{ 0xFF66, 0xFFBE, 1},
{ 0xFFC2, 0xFFC7, 1},
{ 0xFFCA, 0xFFCF, 1},
{ 0xFFD2, 0xFFD7, 1},
{ 0xFFDA, 0xFFDC, 1},
{0x00010000, 0x0001000B, 1},
{0x0001000D, 0x00010026, 1},
{0x00010028, 0x0001003A, 1},
{0x0001003C, 0x0001003D, 1},
{0x0001003F, 0x0001004D, 1},
{0x00010050, 0x0001005D, 1},
{0x00010080, 0x000100FA, 1},
{0x00010140, 0x00010174, 1},
{0x00010280, 0x0001029C, 1},
{0x000102A0, 0x000102D0, 1},
{0x00010300, 0x0001031E, 1},
{0x00010330, 0x0001034A, 1},
{0x00010380, 0x0001039D, 1},
{0x000103A0, 0x000103C3, 1},
{0x000103C8, 0x000103CF, 1},
{0x000103D1, 0x000103D5, 1},
{0x00010400, 0x0001044F, 1},
{0x00010450, 0x0001047F, 1},
{0x00010480, 0x0001049D, 1},
{0x000104A0, 0x000104A9, 1},
{0x00010800, 0x00010805, 1},
{0x00010808, 0, 0},
{0x0001080A, 0x00010835, 1},
{0x00010837, 0x00010838, 1},
{0x0001083C, 0, 0},
{0x0001083F, 0, 0},
{0x00010900, 0x00010915, 1},
{0x00010A00, 0, 0},
{0x00010A10, 0x00010A13, 1},
{0x00010A15, 0x00010A17, 1},
{0x00010A19, 0x00010A33, 1},
{0x00012000, 0x0001236E, 1},
{0x00012400, 0x00012462, 1},
{0x0001D400, 0x0001D454, 1},
{0x0001D456, 0x0001D49C, 1},
{0x0001D49E, 0x0001D49F, 1},
{0x0001D4A2, 0, 0},
{0x0001D4A5, 0x0001D4A6, 1},
{0x0001D4A9, 0x0001D4AC, 1},
{0x0001D4AE, 0x0001D4B9, 1},
{0x0001D4BB, 0, 0},
{0x0001D4BD, 0x0001D4C3, 1},
{0x0001D4C5, 0x0001D505, 1},
{0x0001D507, 0x0001D50A, 1},
{0x0001D50D, 0x0001D514, 1},
{0x0001D516, 0x0001D51C, 1},
{0x0001D51E, 0x0001D539, 1},
{0x0001D53B, 0x0001D53E, 1},
{0x0001D540, 0x0001D544, 1},
{0x0001D546, 0, 0},
{0x0001D54A, 0x0001D550, 1},
{0x0001D552, 0x0001D6A5, 1},
{0x0001D6A8, 0x0001D6C0, 1},
{0x0001D6C2, 0x0001D6DA, 1},
{0x0001D6DC, 0x0001D6FA, 1},
{0x0001D6FC, 0x0001D714, 1},
{0x0001D716, 0x0001D734, 1},
{0x0001D736, 0x0001D74E, 1},
{0x0001D750, 0x0001D76E, 1},
{0x0001D770, 0x0001D788, 1},
{0x0001D78A, 0x0001D7A8, 1},
{0x0001D7AA, 0x0001D7C2, 1},
{0x0001D7C4, 0x0001D7CB, 1},
{0x0001D7CE, 0x0001D7FF, 1},
{0x00020000, 0x0002A6D6, 1},
{0x0002F800, 0x0002FA1D, 1},
{ 0x0660, 0x0669, 1},
{ 0x06F0, 0x06F9, 1},
{ 0x0966, 0x096F, 1},
{ 0x09E6, 0x09EF, 1},
{ 0x0A66, 0x0A6F, 1},
{ 0x0AE6, 0x0AEF, 1},
{ 0x0B66, 0x0B6F, 1},
{ 0x0BE6, 0x0BEF, 1},
{ 0x0C66, 0x0C6F, 1},
{ 0x0C78, 0x0C7F, 1},
{ 0x0CE6, 0x0CEF, 1},
{ 0x0D66, 0x0D75, 1},
{ 0x0D70, 0x0D75, 1},
{ 0x0E50, 0x0E59, 1},
{ 0x0ED0, 0x0ED9, 1},
{ 0x0F20, 0x0F29, 1},
{ 0x1040, 0x1049, 1},
{ 0x17E0, 0x17E9, 1},
{ 0x1810, 0x1819, 1},
{ 0x1BB0, 0x1BB9, 1},
{ 0x1C40, 0x1C49, 1},
{ 0x1C50, 0x1C59, 1},
{ 0xA620, 0xA629, 1},
{ 0xA8D0, 0xA8D9, 1},
{ 0xA900, 0xA909, 1},
{ 0xAA50, 0xAA59, 1},
{ 0xFF10, 0xFF19, 1},
/* END::UTF8TABLE */
};
static inline size_t utf8towc(unsigned *wc, const unsigned char *uc, size_t len)
{
unsigned char ub = utf8_mblen[*uc];
if (!ub || ub > len || ub > 4) {
return 0;
}
*wc = *uc & utf8_mask[ub];
switch (ub) {
case 4:
if ((uc[1] & 0xc0) != 0x80) {
return 0;
}
*wc <<= 6;
*wc += *++uc & 0x3f;
/* no break */
case 3:
if ((uc[1] & 0xc0) != 0x80) {
return 0;
}
*wc <<= 6;
*wc += *++uc & 0x3f;
/* no break */
case 2:
if ((uc[1] & 0xc0) != 0x80) {
return 0;
}
*wc <<= 6;
*wc += *++uc & 0x3f;
/* no break */
case 1:
break;
default:
return 0;
}
return ub;
}
static inline zend_bool isualpha(unsigned ch)
{
unsigned i = 0, j;
PHP_HTTP_DUFF(sizeof(utf8_ranges)/sizeof(utf8_range_t),
if (utf8_ranges[i].start == ch) {
return 1;
} else if (utf8_ranges[i].start <= ch && utf8_ranges[i].end >= ch) {
if (utf8_ranges[i].step == 1) {
return 1;
}
for (j = utf8_ranges[i].start; j <= utf8_ranges[i].end; j+= utf8_ranges[i].step) {
if (ch == j) {
return 1;
}
}
return 0;
}
++i;
);
return 0;
}
static inline zend_bool isualnum(unsigned ch)
{
/* digits */
if (ch >= 0x30 && ch <= 0x39) {
return 1;
}
return isualpha(ch);
}
static inline size_t wctoutf16(unsigned short u16[2], unsigned wc)
{
if (wc > 0x10ffff || (wc >= 0xd800 && wc <= 0xdfff)) {
return 0;
}
if (wc <= 0xffff) {
u16[0] = (unsigned short) wc;
return 1;
}
wc -= 0x10000;
u16[0] = (unsigned short) ((wc >> 10) + 0xd800);
u16[1] = (unsigned short) ((wc & 0x3ff) + 0xdc00);
return 2;
}
static inline size_t utf16towc(unsigned *wc, unsigned short *u16_str, size_t u16_len)
{
if (u16_len < 1) {
return 0;
}
if (u16_str[0] - 0xd800 >= 0x800) {
*wc = u16_str[0];
return 1;
}
if (u16_len < 2 || (u16_str[0] & 0xfffffc00) != 0xd800 || (u16_str[1] & 0xfffffc00) != 0xdc00) {
return 0;
}
*wc = (u16_str[0] << 10) + u16_str[1] - 0x35fdc00;
return 2;
}
#endif /* PHP_HTTP_UTF8_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_version.c 0000644 0001750 0000144 00000004676 12667772426 016727 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#include "php_http_api.h"
php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor)
{
if (!v) {
v = emalloc(sizeof(*v));
}
v->major = major;
v->minor = minor;
return v;
}
php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str)
{
long major, minor;
char separator = 0;
register const char *ptr = str;
switch (*ptr) {
case 'h':
case 'H':
++ptr; if (*ptr != 't' && *ptr != 'T') break;
++ptr; if (*ptr != 't' && *ptr != 'T') break;
++ptr; if (*ptr != 'p' && *ptr != 'P') break;
++ptr; if (*ptr != '/') break;
++ptr;
/* no break */
default:
/* rfc7230#2.6 The HTTP version number consists of two decimal digits separated by a "." (period or decimal point) */
major = *ptr++ - '0';
if (major >= 0 && major <= 9) {
separator = *ptr++;
if (separator) {
if (separator != '.' && separator != ',') {
php_error_docref(NULL, E_NOTICE, "Non-standard version separator '%c' in HTTP protocol version '%s'", separator, ptr - 2);
}
minor = *ptr - '0';
if (minor >= 0 && minor <= 9) {
return php_http_version_init(v, major, minor);
}
}
}
}
php_error_docref(NULL, E_WARNING, "Could not parse HTTP protocol version '%s'", str);
return NULL;
}
void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post)
{
*len = spprintf(str, 0, "%s%u.%u%s", pre ? pre : "", v->major, v->minor, post ? post : "");
}
void php_http_version_dtor(php_http_version_t *v)
{
(void) v;
}
void php_http_version_free(php_http_version_t **v)
{
if (*v) {
php_http_version_dtor(*v);
efree(*v);
*v = NULL;
}
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/src/php_http_version.h 0000644 0001750 0000144 00000002672 12667772426 016726 0 ustar mike users /*
+--------------------------------------------------------------------+
| PECL :: http |
+--------------------------------------------------------------------+
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the conditions mentioned |
| in the accompanying LICENSE file are met. |
+--------------------------------------------------------------------+
| Copyright (c) 2004-2014, Michael Wallner |
+--------------------------------------------------------------------+
*/
#ifndef PHP_HTTP_VERSION_H
#define PHP_HTTP_VERSION_H
typedef struct php_http_version {
unsigned major;
unsigned minor;
} php_http_version_t;
PHP_HTTP_API php_http_version_t *php_http_version_init(php_http_version_t *v, unsigned major, unsigned minor);
PHP_HTTP_API php_http_version_t *php_http_version_parse(php_http_version_t *v, const char *str);
PHP_HTTP_API void php_http_version_to_string(php_http_version_t *v, char **str, size_t *len, const char *pre, const char *post);
PHP_HTTP_API void php_http_version_dtor(php_http_version_t *v);
PHP_HTTP_API void php_http_version_free(php_http_version_t **v);
#endif /* PHP_HTTP_VERSION_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
pecl_http-3.0.1/tests/data/bug71719.bin 0000644 0001750 0000144 00000000400 12667772426 016311 0 ustar mike users ¬Td 5 HTTP/1.1
A΅_eptA eg²²²²²²²²²²²²²²²²²²²²Υ²²²²²²²²²²²²²²²°°A HTTP/1.1
A΅_eptABCDEFGHI²²²²²²²²²²²²²²²²²²²²²²²²²TTP//X-Csrf-Token:1.0 HTTP/.0 ²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² e: Mg
²²΄²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²² eDate: Mg
pecl_http-3.0.1/tests/data/message_r_content_range.txt 0000644 0001750 0000144 00000000265 12667772426 022056 0 ustar mike users PUT / HTTP/1.1
User-Agent: PECL_HTTP/2.3.0dev PHP/5.6.6-dev libcurl/7.41.0-DEV
Host: localhost:8000
Accept: */*
Expect: 100-continue
Content-Length: 3
Content-Range: bytes 1-2/3
23 pecl_http-3.0.1/tests/data/message_r_multipart_put.txt 0000644 0001750 0000144 00000004766 12667772426 022153 0 ustar mike users PUT /docs/ HTTP/1.1
User-Agent: curl/7.24.0 (x86_64-unknown-linux-gnu) libcurl/7.24.0 OpenSSL/1.0.0g zlib/1.2.6 libssh2/1.3.0
Host: drop
Accept: */*
Content-Length: 2273
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------6e182425881c
------------------------------6e182425881c
Content-Disposition: form-data; name="LICENSE"; filename="LICENSE"
Content-Type: application/octet-stream
Copyright (c) 2011-2012, Michael Wallner .
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
------------------------------6e182425881c
Content-Disposition: form-data; name="composer"; filename="composer.json"
Content-Type: application/octet-stream
{
"name": "mike_php_net/autocracy",
"type": "library",
"description": "http\\Controller preserves your autocracy",
"keywords": ["http", "controller", "pecl", "pecl_http"],
"homepage": "http://github.com/mike-php-net/autocracy",
"license": "BSD-2",
"authors": [
{
"name": "Michael Wallner",
"email": "mike@php.net"
}
],
"require": {
"php": ">=5.4.0",
"pecl/pecl_http": "2.*"
},
"autoload": {
"psr-0": {
"http\\Controller": "lib"
}
}
}
------------------------------6e182425881c--
pecl_http-3.0.1/tests/data/message_rr_empty.txt 0000644 0001750 0000144 00000000610 12667772426 020542 0 ustar mike users GET /default/empty.txt HTTP/1.1
Host: localhost
Connection: close
HTTP/1.1 200 OK
Date: Wed, 25 Aug 2010 12:11:44 GMT
Server: Apache/2.2.16 (Unix)
mod_ssl/2.2.16
OpenSSL/1.0.0a
mod_fastcgi/2.4.6
Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT
ETag: "2002a-0-48549d615a35c"
Accept-Ranges: bytes
Content-Length: 0
Vary: Accept-Encoding
Connection: close
Content-Type: text/plain
pecl_http-3.0.1/tests/data/message_rr_empty_chunked.txt 0000644 0001750 0000144 00000000473 12667772426 022252 0 ustar mike users GET /default/empty.php HTTP/1.1
Connection: close
Host: localhost
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2010 11:41:02 GMT
Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6
X-Powered-By: PHP/5.3.3
Vary: Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Content-Type: text/html
0
pecl_http-3.0.1/tests/data/message_rr_empty_gzip.txt 0000644 0001750 0000144 00000000673 12667772426 021604 0 ustar mike users GET /default/empty.txt HTTP/1.1
Host: localhost
Accept-Encoding: gzip
Connection: close
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2010 09:55:09 GMT
Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6
Last-Modified: Wed, 28 Apr 2010 10:54:37 GMT
ETag: "2002a-0-48549d615a35c"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 20
Connection: close
Content-Type: text/plain
0;vL
pecl_http-3.0.1/tests/data/message_rr_helloworld_chunked.txt 0000644 0001750 0000144 00000000474 12667772426 023270 0 ustar mike users GET /cgi-bin/chunked.sh HTTP/1.1
Host: localhost
Connection: close
HTTP/1.1 200 OK
Date: Thu, 26 Aug 2010 12:51:28 GMT
Server: Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6
Vary: Accept-Encoding
Connection: close
Transfer-Encoding: chunked
Content-Type: text/plain
5
Hello
2
,
7
World!
0
pecl_http-3.0.1/tests/data/urls.txt 0000644 0001750 0000144 00000002023 12667772426 016162 0 ustar mike users http://www.microsoft.com
http://www.opensource.org
http://www.google.com
http://www.yahoo.com
http://www.ibm.com
http://www.mysql.com
http://www.oracle.com
http://www.ripe.net
http://www.iana.org
http://www.amazon.com
http://www.netcraft.com
http://www.heise.de
http://www.chip.de
http://www.ca.com
http://www.cnet.com
http://www.news.com
http://www.cnn.com
http://www.wikipedia.org
http://www.dell.com
http://www.hp.com
http://www.cert.org
http://www.mit.edu
http://www.nist.gov
http://www.ebay.com
http://www.postgresql.org
http://www.uefa.com
http://www.ieee.org
http://www.apple.com
http://www.sony.com
http://www.symantec.com
http://www.zdnet.com
http://www.fujitsu.com
http://www.supermicro.com
http://www.hotmail.com
http://www.ecma.com
http://www.bbc.co.uk
http://news.google.com
http://www.foxnews.com
http://www.msn.com
http://www.wired.com
http://www.sky.com
http://www.usatoday.com
http://www.cbs.com
http://www.nbc.com
http://slashdot.org
http://www.bloglines.com
http://www.freecode.org
http://www.newslink.org
http://www.un.org
pecl_http-3.0.1/tests/helper/html/index.html 0000644 0001750 0000144 00000000210 12667772426 017737 0 ustar mike users
HTTP2
Nothing to see here.
pecl_http-3.0.1/tests/helper/cookie.inc 0000644 0001750 0000144 00000000477 12667772426 016761 0 ustar mike users getHeader("cookie"));
$response = new http\Env\Response;
$response->setCookie($cookies->setCookie("counter", $cookies->getCookie("counter")+1));
$response->send($client);
});
pecl_http-3.0.1/tests/helper/dump.inc 0000644 0001750 0000144 00000001163 12667772426 016446 0 ustar mike users $val) {
fprintf($stream, "%s: %s\n", $key, $val);
}
fprintf($stream, "\n");
}
function dump_message($stream, http\Message $msg, $parent = false) {
if (!is_resource($stream)) {
$stream = fopen("php://output", "w");
}
fprintf($stream, "%s\n", $msg->getInfo());
dump_headers($stream, $msg->getHeaders());
$msg->getBody()->toStream($stream);
if ($parent && ($msg = $msg->getParentMessage())) {
dump_message($stream, $msg, true);
}
}
?> pecl_http-3.0.1/tests/helper/http2.crt 0000644 0001750 0000144 00000002230 12667772426 016555 0 ustar mike users -----BEGIN CERTIFICATE-----
MIIDNzCCAh+gAwIBAgIJAKOw1awbt7aIMA0GCSqGSIb3DQEBCwUAMDIxCzAJBgNV
BAYTAkFUMQ8wDQYDVQQKDAZQSFAgUUExEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0x
NTAyMTIxMjQ2NTRaFw0xNzExMDcxMjQ2NTRaMDIxCzAJBgNVBAYTAkFUMQ8wDQYD
VQQKDAZQSFAgUUExEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAMxa+A6xEKQOYme55nQyu0qpvvGB4c4wGBNa6X6YAEzE
Hc19Nbix02UZWQgHM1dmBhbVDW3stO42CQmcViIKfAy5R1A9UZjUcn9nQpaxL/sp
9LrrCANyljISXS40QcBvhCzmcUvDWBRhVTGjV+QTaYmmaM+8hJJJM6W7ByIP22Zv
jHoAnzTx9sjs+OMyWmjYT9pWv6aE+u5iSC8bn3B0GgtfPwoPqDF8ePxIMBpmtbk7
JqXFzHxTVywkypnsF34XK94QjpvRcFGSg/Dc1TopJG2Wfq8hxwtoKerSlL5tyKy0
ZrltxCiLkfVZixwNZEqkg7jPSUvLS299mBrwy+ikmr8CAwEAAaNQME4wHQYDVR0O
BBYEFDiHynoXXjMChfYhc1k7TNtU8ey0MB8GA1UdIwQYMBaAFDiHynoXXjMChfYh
c1k7TNtU8ey0MAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAGD9GERC
uJv+oHfMwkNkDV5ZB4F+SQPzXVxDx+rJm1aGJs9PcwPNiV5GweXbvgcnvRAL4h8h
uv3MLQPgVOq0iqp1QPFCoUXxbYYjYzi9FVbR/154sg0uWEHElU2e3fSjcinNRfXD
12232k6HNwSeeZUFQqn2fuk+cae5BsYT8GfsyMq5EfPtG2d8IG+Ji4eEOJeKu4gl
Y33yQnHhw6QKbx8vWaDpZK8qtpapCtLrTtw/nRhX5YV6kMGK+htQUK1etV2O0VQQ
OtDrhOWWaDxQULsHIvCMgTTnZqNQD+Xz4MBm3PGEGi/QUsrEaSQYppb8xxQKZU4X
MyTh7rO5TdNSXmo=
-----END CERTIFICATE-----
pecl_http-3.0.1/tests/helper/http2.key 0000644 0001750 0000144 00000003217 12667772426 016563 0 ustar mike users -----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAzFr4DrEQpA5iZ7nmdDK7Sqm+8YHhzjAYE1rpfpgATMQdzX01
uLHTZRlZCAczV2YGFtUNbey07jYJCZxWIgp8DLlHUD1RmNRyf2dClrEv+yn0uusI
A3KWMhJdLjRBwG+ELOZxS8NYFGFVMaNX5BNpiaZoz7yEkkkzpbsHIg/bZm+MegCf
NPH2yOz44zJaaNhP2la/poT67mJILxufcHQaC18/Cg+oMXx4/EgwGma1uTsmpcXM
fFNXLCTKmewXfhcr3hCOm9FwUZKD8NzVOikkbZZ+ryHHC2gp6tKUvm3IrLRmuW3E
KIuR9VmLHA1kSqSDuM9JS8tLb32YGvDL6KSavwIDAQABAoIBAQCzUdAB9FYJ36Vy
J6qVpD69EZ7ABZzDdWhq84eY0oDQ2/ba7lhJraE2QbviU481zgzh1CponyFVNo1P
paPfUxvvflWZj3Ueiq2+JjpESU81MmfR7ZOmktJBNeQWOzzHRBPT4pLgTJXprE85
s3/YX0BozWGDiIU8aIetkiR8OzXm97+BrJWiPFl733dGnHvfpHAZu/PwKZc2+8ft
CnQw4GHRhTBWCVNj29HLwm+CA66zQqiAXItgijWMKzs+9ciPn+aCsCnZDNF+o1zs
4pWt60CtIJQtD3r3rSRy7nBaCKcTrr/JU3FvwqKdunuUBUsuYeSaMBokW67kpVzS
dO9L9p6BAoGBAP+pvcAd8qfC1WIrn9vka3aK25ulbYSCae3YaWmABc93INJPBMvO
GrcUuaLKiQC1oou+E64vGyJ9MeEFwxh2zbvU75a9ezeKAajgaq92ciMX2QqREh0N
IntNOc4w7eB6BK8NpaDXNvTtxNWMvlYyhVN0M7FVQRmYJfCJdnTZAkzvAoGBAMyf
6rvWuc/wmIcAtBVe+jIeQ69EJJ/Idcjk0JUm6lFECAAraPpsCglha+wTHWWRQZ9u
pPqBnb7QPjevU+3bZHnMvGoEzd5F4Rw74J+p5EZeMUJpuKmon7Ekzemcb0DV+qX9
NorB781D2Z0MG9SCptKyKpN5TPHTjGz4BB3mLC8xAoGAdq99/ynn9ClmleRameI4
YRelS2RIqzM/qcLFbMyZ5e4PtpIoT9SmYkekxgXwA/xOMUFUMZB8sE4eUbAzGbBN
Yd1APGJKSUYv7w3/eOUrp07y2wzts77dOxBmvWnJhGQguINFWJ2QTbPzpI9p7OoX
Kt7PAIvrZM5VDo1CCIyVnNECgYEAgLmpZXlzcwicK3GZ2EfjhVvcoIlxsMLetf6b
6PiON4lgrxqf88m7lqMezWhI+fgjHDTyvFSF89/1A/rcBaoazzSo4tka2VWEg8p3
SHoMDOh8fJcdgD2AGGRa1TeAFX2HLJzajvfp72tbnpxbdZircah7eEK60PaQRIzR
qi1+ZkECgYEAi7GkO7Ey98DppLnt7567veQoEj0u8ixTlCyJ4V278nHR5+6eAZP5
PfdZVC3MtKGLnxrrPTVUy5wU0hR6Gk9EVDmrAF8TgJdnZFlBK7X23eWZ0q4qO/eO
3xIi+UrNwLag8BjYOr32nP/i+F+TLikgRIFR4oiZjk867+ofkTXmNFA=
-----END RSA PRIVATE KEY-----
pecl_http-3.0.1/tests/helper/pipeline.inc 0000644 0001750 0000144 00000001636 12667772426 017313 0 ustar mike users setEnvRequest($msg)
->setHeader("X-Req", $msg->getRequestUrl())
->send($client);
}
serve(function($client) {
$R = array(STDIN); $W = $E = array();
if (!stream_select($R, $W, $E, 10, 0)) {
logger("Client %d timed out", (int) $client);
return;
}
$count = trim(fgets(STDIN));
logger("Expecting %d messages from client %d", $count, (int) $client);
/* the peek message */
respond($client, new http\Message($client, false));
logger("Handled the peek request of client %d", (int) $client);
/* pipelined messages */
$req = array();
for ($i=0; $i < $count; ++ $i) {
$req[] = new http\Message($client, false);
logger("Read request no. %d from client %d", $i+1, (int) $client);
}
foreach ($req as $i => $msg) {
respond($client, $msg);
logger("Sent response no. %d to client %d", $i+1, (int) $client);
}
});
pecl_http-3.0.1/tests/helper/proxy.inc 0000644 0001750 0000144 00000001360 12667772426 016661 0 ustar mike users getHeader("Proxy-Connection")) {
$response = new http\Env\Response;
$response->setEnvRequest($request);
$response->send($client);
/* soak up the request following the connect */
new http\Message($client, false);
}
/* return the initial message as response body */
$response = new http\Env\Response;
$response->setHeader("X-Request-Content-Length", $request->getBody()->stat("size"));
/* avoid OOM with $response->getBody()->append($request); */
dump_message($response->getBody()->getResource(), $request);
$response->send($client);
});
pecl_http-3.0.1/tests/helper/server.inc 0000644 0001750 0000144 00000007221 12667772426 017010 0 ustar mike users getMessage());
/* ignore disconnect */
if ($ex->getMessage() !== "Empty message received from stream") {
fprintf(STDERR, "%s\n", $ex);
}
break;
}
}
} while ($select);
return;
}
}
}
function server($handler, $cb) {
$args = explode(' ', getenv('TEST_PHP_ARGS'));
$args[] = __DIR__."/$handler";
foreach ($args as $k => $v) {
if (!$v) unset($args[$k]);
}
proc(PHP_BIN, $args, $cb);
}
function nghttpd($cb) {
$spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w"));
$offset = rand(0,2000);
foreach (range(8000+$offset, 9000+$offset) as $port) {
$comm = "exec nghttpd -d html $port http2.key http2.crt";
if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) {
$stdin = $pipes[0];
$stdout = $pipes[1];
$stderr = $pipes[2];
usleep(50000);
$status = proc_get_status($proc);
if (!$status["running"]) {
continue;
}
try {
$cb($port, $stdin, $stdout, $stderr);
} catch (Exception $e) {
echo $e,"\n";
}
proc_terminate($proc);
fpassthru($stderr);
fpassthru($stdout);
return;
}
}
}
function proc($bin, $args, $cb) {
$spec = array(array("pipe","r"), array("pipe","w"), array("pipe","w"));
$comm = escapeshellcmd($bin) . " ". implode(" ", array_map("escapeshellarg", $args));
if (($proc = proc_open($comm, $spec, $pipes, __DIR__))) {
$stdin = $pipes[0];
$stdout = $pipes[1];
$stderr = $pipes[2];
do {
$port = trim(fgets($stderr));
$R = array($stderr); $W = array(); $E = array();
} while (is_numeric($port) && stream_select($R, $W, $E, 0, 10000));
if (is_numeric($port)) {
try {
$cb($port, $stdin, $stdout, $stderr);
} catch (Exception $e) {
echo $e,"\n";
}
}
proc_terminate($proc);
fpassthru($stderr);
fpassthru($stdout);
}
}
pecl_http-3.0.1/tests/helper/upload.inc 0000644 0001750 0000144 00000001067 12667772426 016770 0 ustar mike users getHeader("Expect") === "100-continue") {
$response = new http\Env\Response;
$response->setEnvRequest($request);
$response->setResponseCode(100);
$response->send($client);
}
/* return the initial message as response body */
$response = new http\Env\Response;
/* avoid OOM with $response->getBody()->append($request); */
dump_message($response->getBody()->getResource(), $request);
$response->send($client);
});
pecl_http-3.0.1/tests/skipif.inc 0000644 0001750 0000144 00000001413 12667772426 015505 0 ustar mike users
--FILE--
'utm_source=changed'), http\Url::JOIN_QUERY), PHP_EOL, PHP_EOL;
// Replacing the host
echo new http\Url($url, array('host' => 'www.google.com')), PHP_EOL, PHP_EOL;
// Generating a query string from scratch
echo new http\QueryString(array(
'bar.baz' => 'blah',
'utm_source' => 'google',
'utm_campaign' => 'somethingelse',
'blat' => null,
)), PHP_EOL, PHP_EOL;
?>
DONE
--EXPECT--
http://www.example.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat
http://www.example.com/foobar?bar.baz=blah&utm_source=changed&utm_campaign=somethingelse
http://www.google.com/foobar?bar.baz=blah&utm_source=google&utm_campaign=somethingelse&blat
bar.baz=blah&utm_source=google&utm_campaign=somethingelse
DONE
pecl_http-3.0.1/tests/bug66388.phpt 0000644 0001750 0000144 00000001044 12667772426 015616 0 ustar mike users --TEST--
Bug #66388 (Crash on POST with Content-Length:0 and untouched body)
--SKIPIF--
--FILE--
0
)
);
$client->enqueue($request);
echo $client->send()->getResponse()->getResponseCode();
});
?>
===DONE===
--EXPECTF--
Test
200
===DONE===
pecl_http-3.0.1/tests/bug66891.phpt 0000644 0001750 0000144 00000000456 12667772426 015623 0 ustar mike users --TEST--
Bug #66891 (Unexpected HTTP 401 after NTLM authentication)
--SKIPIF--
--GET--
dummy=1
--FILE--
setResponseCode(200);
$r->send();
var_dump(http\Env::getResponseCode());
?>
--EXPECT--
int(200) pecl_http-3.0.1/tests/bug67932.phpt 0000644 0001750 0000144 00000000443 12667772426 015614 0 ustar mike users --TEST--
Bug #67932 (php://input always empty)
--SKIPIF--
--PUT--
Content-Type: text/xml
test
--FILE--
--EXPECT--
test