package.xml0000644000175000001440000007215512667772426012074 0ustar mikeusers 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.h0000644000175000001440000000765512667772426016020 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000002753512667772426016512 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000002440712667772426016512 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001352712667772426015155 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000011665412667772426016520 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000001457312667772426016522 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000024715712667772426017550 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000215312667772426017536 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000002321212667772426020253 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000202712667772426020261 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001121612667772426020422 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000203512667772426020426 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000007032512667772426016505 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000740712667772426016513 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000000673712667772426016207 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000216312667772426016201 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000011062012667772426017013 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000001741112667772426017024 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000005415212667772426016024 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000734412667772426016032 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000002327012667772426017571 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000175312667772426017600 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000013010412667772426017732 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000634012667772426017743 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000000666712667772426016164 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000300712667772426016152 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001445512667772426017234 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000441212667772426017231 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000002734512667772426016525 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000172212667772426016521 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000004246112667772426020040 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000621212667772426020037 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000003062212667772426016460 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000303112667772426016457 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001071712667772426016166 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000612012667772426016164 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000006273012667772426017676 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000765512667772426017710 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000017777712667772426016703 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000001131312667772426016655 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000006004112667772426020226 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000675512667772426020247 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001456212667772426016170 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000001653612667772426016200 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000001204012667772426017201 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000760612667772426017222 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000000713612667772426016502 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000347712667772426016513 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000000645412667772426016731 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000426412667772426016733 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000011122612667772426016513 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000462112667772426016520 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000005354512667772426017635 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000353012667772426017627 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000704112667772426020247 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000014312512667772426016035 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000001033212667772426016033 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000004463712667772426016136 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.c0000644000175000001440000000467612667772426016727 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.h0000644000175000001440000000267212667772426016726 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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.bin0000644000175000001440000000040012667772426016311 0ustar mikeusers€¬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.txt0000644000175000001440000000026512667772426022056 0ustar mikeusersPUT / 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 23pecl_http-3.0.1/tests/data/message_r_multipart_put.txt0000644000175000001440000000476612667772426022153 0ustar mikeusersPUT /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.txt0000644000175000001440000000061012667772426020542 0ustar mikeusersGET /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.txt0000644000175000001440000000047312667772426022252 0ustar mikeusersGET /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.txt0000644000175000001440000000067312667772426021604 0ustar mikeusersGET /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.txt0000644000175000001440000000047412667772426023270 0ustar mikeusersGET /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.txt0000644000175000001440000000202312667772426016162 0ustar mikeusershttp://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.html0000644000175000001440000000021012667772426017737 0ustar mikeusers HTTP2 Nothing to see here. pecl_http-3.0.1/tests/helper/cookie.inc0000644000175000001440000000047712667772426016761 0ustar mikeusersgetHeader("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.inc0000644000175000001440000000116312667772426016446 0ustar mikeusers $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.crt0000644000175000001440000000223012667772426016555 0ustar mikeusers-----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.key0000644000175000001440000000321712667772426016563 0ustar mikeusers-----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.inc0000644000175000001440000000163612667772426017313 0ustar mikeuserssetEnvRequest($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.inc0000644000175000001440000000136012667772426016661 0ustar mikeusersgetHeader("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.inc0000644000175000001440000000722112667772426017010 0ustar mikeusersgetMessage()); /* 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.inc0000644000175000001440000000106712667772426016770 0ustar mikeusersgetHeader("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.inc0000644000175000001440000000141312667772426015505 0ustar mikeusers --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.phpt0000644000175000001440000000104412667772426015616 0ustar mikeusers--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.phpt0000644000175000001440000000045612667772426015623 0ustar mikeusers--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.phpt0000644000175000001440000000044312667772426015614 0ustar mikeusers--TEST-- Bug #67932 (php://input always empty) --SKIPIF-- --PUT-- Content-Type: text/xml test --FILE-- --EXPECT-- testpecl_http-3.0.1/tests/bug69000.phpt0000644000175000001440000000241612667772426015602 0ustar mikeusers--TEST-- Bug #69000 (http\Url breaks down with very long URL query strings) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test http://foo.bar/?aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ===DONE=== pecl_http-3.0.1/tests/bug69076.phpt0000644000175000001440000000036412667772426015617 0ustar mikeusers--TEST-- Bug #69076 (URL parsing throws exception on empty query string) --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test http://foo.bar/ ===DONE=== pecl_http-3.0.1/tests/bug69313.phpt0000644000175000001440000000153512667772426015612 0ustar mikeusers--TEST-- Bug #69313 (http\Client doesn't send GET body) --SKIPIF-- --FILE-- setHeader("Content-Type", "text/plain"); $request->getBody()->append("foo"); $client = new http\Client(); $client->enqueue($request); $client->send(); dump_message(null, $client->getResponse()); }); ?> Done --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes Content-Length: %d Etag: "%s" X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 3 GET / HTTP/1.1 Accept: */* Content-Length: 3 Content-Type: text/plain Host: localhost:%d User-Agent: %s X-Original-Content-Length: 3 foo Done pecl_http-3.0.1/tests/bug69357.phpt0000644000175000001440000000146712667772426015626 0ustar mikeusers--TEST-- Bug #69357 (HTTP/1.1 100 Continue overriding subsequent 200 response code with PUT request) --SKIPIF-- --FILE-- append("foo") ); $c = new \http\Client; $c->setOptions(["expect_100_timeout" => 0]); $c->enqueue($r)->send(); var_dump($c->getResponse($r)->getInfo()); var_dump($c->getResponse($r)->getHeaders()); }); ?> ===DONE=== --EXPECTF-- Test string(15) "HTTP/1.1 200 OK" array(4) { ["Accept-Ranges"]=> string(5) "bytes" ["Etag"]=> string(10) ""%x"" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(%d) } ===DONE=== pecl_http-3.0.1/tests/bug71719.phpt0000644000175000001440000000110612667772426015607 0ustar mikeusers--TEST-- Buffer overflow in HTTP url parsing functions --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- Test %r(exception ')?%rhttp\Exception\BadMessageException%r(' with message '|: )%rhttp\Message::__construct(): Could not parse HTTP protocol version 'HTTP/%s.0'%r'?%r in %sbug71719.php:5 Stack trace: #0 %sbug71719.php(5): http\Message->__construct('\x80\xACTd 5 HTTP/1.1...', false) #1 {main} ===DONE=== pecl_http-3.0.1/tests/client001.phpt0000644000175000001440000000046612667772426016130 0ustar mikeusers--TEST-- client drivers --SKIPIF-- --FILE-- Done --EXPECTREGEX-- Test (?:bool\(true\) )+Done pecl_http-3.0.1/tests/client002.phpt0000644000175000001440000000133512667772426016125 0ustar mikeusers--TEST-- client observer --SKIPIF-- --FILE-- getProgressInfo($request) != $progress) { var_dump($progress); } } } server("proxy.inc", function($port, $stdin, $stdout, $stderr) { foreach (http\Client::getAvailableDrivers() as $driver) { $client = new http\Client($driver); $client->attach(new Observer); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client->send(); } }); ?> Done --EXPECTREGEX-- Test P+ Done pecl_http-3.0.1/tests/client003.phpt0000644000175000001440000000106312667772426016124 0ustar mikeusers--TEST-- client once & wait --SKIPIF-- --FILE-- enqueue($request); while ($client->once()) { $client->wait(.1); } if (!$client->getResponse()) { var_dump($client); } } }); ?> Done --EXPECT-- Test Done pecl_http-3.0.1/tests/client004.phpt0000644000175000001440000000146012667772426016126 0ustar mikeusers--TEST-- client reset --SKIPIF-- --FILE-- enqueue($request)->send(); if (!($client->getResponse($request) instanceof http\Client\Response)) { var_dump($client); } try { $client->enqueue($request); } catch (Exception $e) { echo $e->getMessage(),"\n"; } $client->reset(); if (($response = $client->getResponse())) { var_dump($response); } $client->enqueue($request); } }); ?> Done --EXPECTREGEX-- Test (?:Failed to enqueue request; request already in queue )+Done pecl_http-3.0.1/tests/client005.phpt0000644000175000001440000000106612667772426016131 0ustar mikeusers--TEST-- client response callback --SKIPIF-- --FILE-- enqueue(new http\Client\Request("GET", "http://localhost:$port"), function($response) { echo "R\n"; if (!($response instanceof http\Client\Response)) { var_dump($response); } }); $client->send(); } }); ?> Done --EXPECTREGEX-- Test (?:R )+Done pecl_http-3.0.1/tests/client006.phpt0000644000175000001440000000152312667772426016130 0ustar mikeusers--TEST-- client response callback + dequeue --SKIPIF-- --FILE-- enqueue($request, "response"); $client->send(); try { $client->dequeue($request); } catch (Exception $e) { echo $e->getMessage(),"\n"; } } } }); ?> Done --EXPECTREGEX-- Test (?:(?:R Failed to dequeue request; request not in queue )+)+Done pecl_http-3.0.1/tests/client007.phpt0000644000175000001440000000121112667772426016123 0ustar mikeusers--TEST-- client response callback + requeue --SKIPIF-- --FILE-- requeue($request, "response"); $client->send(); } } }); ?> Done --EXPECTREGEX-- Test (?:R R )+Done pecl_http-3.0.1/tests/client008.phpt0000644000175000001440000000120112667772426016123 0ustar mikeusers--TEST-- client features --SKIPIF-- --FILE-- configure(array("pipelining" => true, "use_eventloop" => true)); $client->enqueue($request); $client->send(); $client->enqueue(clone $request); $client->enqueue(clone $request); $client->send(); while ($client->getResponse()) { echo "R\n"; } }); ?> Done --EXPECTREGEX-- Test (?:R R R )+Done pecl_http-3.0.1/tests/client009.phpt0000644000175000001440000000172512667772426016137 0ustar mikeusers--TEST-- client static cookies --SKIPIF-- --FILE-- setCookies(array("test" => "bar")); $client->addCookies(array("foo" => "test")); $client->enqueue($request); $client->send(); var_dump($client->getResponse()->getBody()->toString()); $request->setOptions(array("cookies" => x($client->getCookies()))); $client->requeue($request); $client->send(); var_dump($client->getResponse()->getBody()->toString()); } ?> Done --EXPECTREGEX-- Test (?:string\(46\) "Array\n\(\n \[test\] \=\> bar\n \[foo\] \=\> test\n\)\n"\nstring\(46\) "Array\n\(\n \[test\] \=\> test\n \[foo\] \=\> bar\n\)\n"\n)+Done pecl_http-3.0.1/tests/client010.phpt0000644000175000001440000000150312667772426016121 0ustar mikeusers--TEST-- client upload --SKIPIF-- --FILE-- Array \( \[name\] \=\> client010\.php \[type\] \=\> text\/plain \[tmp_name\] \=\> .+ \[error\] \=\> 0 \[size\] \=\> \d+ \) \) )+/'; $request = new http\Client\Request("POST", "http://dev.iworks.at/ext-http/.print_request.php"); $request->getBody()->addForm(null, array("file"=>__FILE__, "name"=>"upload", "type"=>"text/plain")); foreach (http\Client::getAvailableDrivers() as $driver) { $client = new http\Client($driver); $client->enqueue($request)->send(); if (!preg_match($RE, $s = $client->getResponse()->getBody()->toString())) { echo($s); } } ?> Done --EXPECT-- Test Donepecl_http-3.0.1/tests/client011.phpt0000644000175000001440000000246412667772426016131 0ustar mikeusers--TEST-- client history --SKIPIF-- --FILE-- append("foobar"); $request = new http\Client\Request; $request->setBody($body); $request->setRequestMethod("POST"); $request->setRequestUrl("http://dev.iworks.at/ext-http/.print_request.php"); $client = new http\Client; $client->recordHistory = true; $client->enqueue($request)->send(); echo $client->getHistory()->toString(true); $client->requeue($request)->send(); echo $client->getHistory()->toString(true); ?> Done --EXPECTF-- Test POST http://dev.iworks.at/ext-http/.print_request.php HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Vary: %s Content-Type: text/html Date: %s Server: %s X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" POST http://dev.iworks.at/ext-http/.print_request.php HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Vary: %s Content-Type: text/html Date: %s Server: %s X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" POST http://dev.iworks.at/ext-http/.print_request.php HTTP/1.1 Content-Length: 6 foobar HTTP/1.1 200 OK Vary: %s Content-Type: text/html Date: %s Server: %s X-Original-Transfer-Encoding: chunked Content-Length: 19 string(6) "foobar" Done pecl_http-3.0.1/tests/client012.phpt0000644000175000001440000000130412667772426016122 0ustar mikeusers--TEST-- client ssl --SKIPIF-- --FILE-- setSslOptions(array("verifypeer" => true)); $client->addSslOptions(array("verifyhost" => 2)); var_dump( array( "verifypeer" => true, "verifyhost" => 2, ) === $client->getSslOptions() ); $client->enqueue($req = new http\Client\Request("GET", "https://twitter.com/")); $client->send(); $ti = (array) $client->getTransferInfo($req); var_dump(array_key_exists("ssl_engines", $ti)); var_dump(0 < count($ti["ssl_engines"] || $ti["tls_session"]["backend"] != "openssl")); ?> Done --EXPECTF-- Test bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/client013.phpt0000644000175000001440000000342612667772426016132 0ustar mikeusers--TEST-- client observers --SKIPIF-- --FILE-- getProgressInfo($r)) $c->pi .= "-"; } } class ProgressObserver2 implements SplObserver { function update(SplSubject $c, $r = null) { if ($c->getProgressInfo($r)) $c->pi .= "."; } } class CallbackObserver implements SplObserver { public $callback; function __construct($callback) { $this->callback = $callback; } function update(SplSubject $c, $r = null) { call_user_func($this->callback, $c, $r); } } server("proxy.inc", function($port) { $client = new Client; $client->attach($o1 = new ProgressObserver1); $client->attach($o2 = new ProgressObserver2); $client->attach( $o3 = new CallbackObserver( function ($c, $r) { $p = (array) $c->getProgressInfo($r); var_dump(array_key_exists("started", $p)); var_dump(array_key_exists("finished", $p)); var_dump(array_key_exists("dlnow", $p)); var_dump(array_key_exists("ulnow", $p)); var_dump(array_key_exists("dltotal", $p)); var_dump(array_key_exists("ultotal", $p)); var_dump(array_key_exists("info", $p)); } ) ); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"))->send(); var_dump(1 === preg_match("/(\.-)+/", $client->pi)); var_dump(3 === count($client->getObservers())); $client->detach($o1); var_dump(2 === count($client->getObservers())); $client->detach($o2); var_dump(1 === count($client->getObservers())); $client->detach($o3); var_dump(0 === count($client->getObservers())); }); ?> Done --EXPECTREGEX-- Test\n(bool\(true\)\n)+Done pecl_http-3.0.1/tests/client014.phpt0000644000175000001440000000104612667772426016127 0ustar mikeusers--TEST-- reset content length when resetting body --SKIPIF-- --FILE-- setBody(new http\Message\Body(fopen(__FILE__, "r"))); $client->enqueue($request); var_dump($request->getHeader("Content-Length")); $request->setBody(new http\Message\Body); $client->requeue($request); var_dump($request->getHeader("Content-Length")); ?> ===DONE=== --EXPECTF-- Test int(379) bool(false) ===DONE=== pecl_http-3.0.1/tests/client015.phpt0000644000175000001440000000140612667772426016130 0ustar mikeusers--TEST-- http client event base --SKIPIF-- --FILE-- configure(array("use_eventloop" => true)); $client2->configure(array("use_eventloop" => true)); $client1->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client2->enqueue(new http\Client\Request("GET", "http://localhost:$port/")); $client1->send(); if (($r = $client1->getResponse())) { var_dump($r->getTransferInfo("response_code")); } if (($r = $client2->getResponse())) { var_dump($r->getTransferInfo("response_code")); } }); ?> DONE --EXPECT-- Test int(200) DONE pecl_http-3.0.1/tests/client016.phpt0000644000175000001440000000114112667772426016125 0ustar mikeusers--TEST-- client once & wait with events --SKIPIF-- --FILE-- configure(array("use_eventloop" => true)); $client->enqueue($request); while ($client->once()) { $client->wait(.1); } if (!$client->getResponse()) { var_dump($client); } } }); ?> Done --EXPECT-- Test Done pecl_http-3.0.1/tests/client017.phpt0000644000175000001440000000106612667772426016134 0ustar mikeusers--TEST-- client request gzip --SKIPIF-- --FILE-- setOptions(array("compress" => true)); $client->enqueue(new http\Client\Request("GET", "http://dev.iworks.at/ext-http/.print_request.php")); $client->send(); echo $client->getResponse(); ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Vary: Accept-Encoding Content-Type: text/html Date: %s Server: %s X-Original-Transfer-Encoding: chunked X-Original-Content-Encoding: gzip ===DONE===pecl_http-3.0.1/tests/client018.phpt0000644000175000001440000000235512667772426016137 0ustar mikeusers--TEST-- client pipelining --SKIPIF-- --FILE-- configure(array("pipelining" => true, "max_host_connections" => 0)); /* this is just to let curl know the server may be capable of pipelining */ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port")); $client->send(); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/1")); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/2")); $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/3")); $client->send(); while (($response = $client->getResponse())) { echo $response; } }); ?> ===DONE=== --EXPECT-- Test HTTP/1.1 200 OK X-Req: /3 Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK X-Req: /2 Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK X-Req: /1 Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK X-Req: / Etag: "" X-Original-Transfer-Encoding: chunked ===DONE=== pecl_http-3.0.1/tests/client019.phpt0000644000175000001440000000201712667772426016133 0ustar mikeusers--TEST-- client proxy - send proxy headers for a proxy request --SKIPIF-- getAvailableOptions()) or die("skip need libcurl with CURLOPT_PROXYHEADER support\n"); ?> --FILE-- setOptions(array( "timeout" => 10, "proxytunnel" => true, "proxyheader" => array("Hello" => "there!"), "proxyhost" => "localhost", "proxyport" => $port, )); try { $c->enqueue($r)->send(); } catch (Exception $e) { echo $e; } echo $c->getResponse()->getBody(); }); ?> ===DONE=== --EXPECTF-- Test Server on port %d CONNECT www.example.com:80 HTTP/1.1 Hello: there! Host: www.example.com:80 Proxy-Connection: Keep-Alive User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s ===DONE=== pecl_http-3.0.1/tests/client020.phpt0000644000175000001440000000137012667772426016124 0ustar mikeusers--TEST-- client proxy - don't send proxy headers for a standard request --SKIPIF-- --FILE-- setOptions(array( "timeout" => 3, "proxyheader" => array("Hello" => "there!"), )); try { $c->enqueue($r)->send(); } catch (Exception $e) { echo $e; } echo $c->getResponse()->getBody(); unset($r, $client); }); ?> ===DONE=== --EXPECTF-- Test Server on port %d GET / HTTP/1.1 Accept: */* Host: localhost:%d User-Agent: PECL_HTTP/%s PHP/%s libcurl/%s ===DONE=== pecl_http-3.0.1/tests/client021.phpt0000644000175000001440000000517012667772426016127 0ustar mikeusers--TEST-- client cookies --SKIPIF-- --FILE-- setOptions(array("cookiestore" => $tmpfile)); server("cookie.inc", function($port) use($request) { $request->setOptions(array("port" => $port)); $client = new http\Client; echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); }); server("cookie.inc", function($port) use($request) { $request->setOptions(array("port" => $port)); $client = new http\Client; echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); }); server("cookie.inc", function($port) use($request) { $request->setOptions(array("port" => $port, "cookiesession" => true)); $client = new http\Client; echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); }); server("cookie.inc", function($port) use($request) { $request->setOptions(array("port" => $port, "cookiesession" => false)); $client = new http\Client; echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); echo $client->requeue($request)->send()->getResponse(); }); unlink($tmpfile); ?> ===DONE=== --EXPECT-- Test HTTP/1.1 200 OK Set-Cookie: counter=1; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=2; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=3; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=4; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=5; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=6; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=1; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=1; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=1; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=2; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=3; Etag: "" X-Original-Transfer-Encoding: chunked HTTP/1.1 200 OK Set-Cookie: counter=4; Etag: "" X-Original-Transfer-Encoding: chunked ===DONE=== pecl_http-3.0.1/tests/client022.phpt0000644000175000001440000000124512667772426016127 0ustar mikeusers--TEST-- client http2 --SKIPIF-- --FILE-- setOptions([ "protocol" => http\Client\Curl\HTTP_VERSION_2_0, "ssl" => [ "cainfo" => __DIR__."/helper/http2.crt", ] ]); $client->enqueue(new http\Client\Request("GET", "https://localhost:$port")); echo $client->send()->getResponse(); }); ?> ===DONE=== --EXPECTF-- Test HTTP/2.0 200 %a HTTP2 Nothing to see here. ===DONE=== pecl_http-3.0.1/tests/client023.phpt0000644000175000001440000000136612667772426016134 0ustar mikeusers--TEST-- client available options and configuration --SKIPIF-- --FILE-- getOptions())) { var_dump($options); } $client->setOptions($avail = $client->getAvailableOptions()); $opt = $client->getOptions(); foreach ($avail as $k => $v) { if (is_array($v)) { $oo = $opt[$k]; foreach ($v as $kk => $vv) { if (isset($vv) && $oo[$kk] !== $vv) { var_dump(array($kk => array($vv, $oo[$kk]))); } } } else if (isset($v) && $opt[$k] !== $v) { var_dump(array($k => array($v, $opt[$k]))); } } var_dump($client === $client->configure($client->getAvailableConfiguration())); ?> ===DONE=== --EXPECT-- Test bool(true) ===DONE=== pecl_http-3.0.1/tests/client024.phpt0000644000175000001440000000071112667772426016126 0ustar mikeusers--TEST-- client deprecated methods --SKIPIF-- --FILE-- enableEvents(false); $client->enablePipelining(false); ?> ===DONE=== --EXPECTF-- Test Deprecated: Function http\Client::enableEvents() is deprecated in %sclient024.php on line %d Deprecated: Function http\Client::enablePipelining() is deprecated in %sclient024.php on line %d ===DONE=== pecl_http-3.0.1/tests/client025.phpt0000644000175000001440000000154012667772426016130 0ustar mikeusers--TEST-- client seek --SKIPIF-- --FILE-- setOptions(array("resume" => 1, "expect_100_timeout" => 0)); $request->getBody()->append("123"); dump_message(null, $client->enqueue($request)->send()->getResponse()); }); // Content-length is 2 instead of 3 in older libcurls ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes Content-Length: %d Etag: "%x" X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 2 PUT / HTTP/1.1 Accept: */* Content-Length: %d Content-Range: bytes 1-2/3 Expect: 100-continue Host: localhost:%d User-Agent: %s X-Original-Content-Length: %d 23===DONE=== pecl_http-3.0.1/tests/client026.phpt0000644000175000001440000000152112667772426016130 0ustar mikeusers--TEST-- client stream 128M --SKIPIF-- --FILE-- setContentType("application/octet-stream"); for ($i = 0, $data = str_repeat("a",1024); $i < 128*1024; ++$i) { $request->getBody()->append($data); } $request->setOptions(array("timeout" => 10, "expect_100_timeout" => 0)); $client->enqueue($request); $client->send(); dump_headers(null, $client->getResponse()->getHeaders()); }); ?> ===DONE=== --EXPECTF-- Test Accept-Ranges: bytes Content-Length: %d Etag: "%x" Last-Modified: %s X-Original-Transfer-Encoding: chunked X-Request-Content-Length: 134217728 ===DONE=== pecl_http-3.0.1/tests/clientrequest001.phpt0000644000175000001440000000074512667772426017541 0ustar mikeusers--TEST-- client request --SKIPIF-- --FILE-- getBody()); var_dump($h === $r->getHeaders()); var_dump($u === $r->getRequestUrl()); var_dump($m === $r->getRequestMethod()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/clientrequest002.phpt0000644000175000001440000000051612667772426017536 0ustar mikeusers--TEST-- client request content type --SKIPIF-- --FILE-- setContentType($ct = "text/plain; charset=utf-8")); var_dump($ct === $r->getContentType()); ?> Done --EXPECT-- Test bool(true) bool(true) Done pecl_http-3.0.1/tests/clientrequest003.phpt0000644000175000001440000000102412667772426017532 0ustar mikeusers--TEST-- client request query --SKIPIF-- --FILE-- getQuery()); var_dump($r === $r->setQuery($q = "foo=bar")); var_dump($q === $r->getQuery()); var_dump($r === $r->addQuery("a[]=1&a[]=2")); var_dump("foo=bar&a%5B0%5D=1&a%5B1%5D=2" === $r->getQuery()); var_dump(null === $r->setQuery(null)->getQuery()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/clientrequest004.phpt0000644000175000001440000000111212667772426017531 0ustar mikeusers--TEST-- client request options --SKIPIF-- --FILE-- setOptions($o = array("redirect"=>5, "timeout"=>5))); var_dump($o === $r->getOptions()); var_dump($r === $r->setOptions(array("timeout"=>50))); $o["timeout"] = 50; var_dump($o === $r->getOptions()); var_dump($r === $r->setSslOptions($o = array("verify_peer"=>false))); var_dump($o === $r->getSslOptions()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/clientresponse001.phpt0000644000175000001440000000156012667772426017703 0ustar mikeusers--TEST-- client response cookie --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { var_dump($cookies->toArray()); } } ?> Done --EXPECTREGEX-- Test (?:array\(7\) \{\n \["cookies"\]\=\>\n array\(2\) \{\n \["foo"\]\=\>\n string\(3\) "bar"\n \["bar"\]\=\>\n string\(3\) "foo"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\-1\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\n)+Done pecl_http-3.0.1/tests/clientresponse002.phpt0000644000175000001440000000223212667772426017701 0ustar mikeusers--TEST-- client response cookies --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse()->getCookies(0, array("comment")) as $cookies) { var_dump($cookies->toArray()); } } ?> Done --EXPECTREGEX-- Test (?:array\(7\) \{\n \["cookies"\]\=\>\n array\(1\) \{\n \["temp"\]\=\>\n string\(1\d\) "\d+\.\d+"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\-1\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\narray\(7\) \{\n \["cookies"\]\=\>\n array\(1\) \{\n \["perm"\]\=\>\n string\(1\d\) "\d+\.\d+"\n \}\n \["extras"\]\=\>\n array\(0\) \{\n \}\n \["flags"\]\=\>\n int\(0\)\n \["expires"\]\=\>\n int\(\d+\)\n \["max\-age"\]\=\>\n int\(\-1\)\n \["path"\]\=\>\n string\(0\) ""\n \["domain"\]\=\>\n string\(0\) ""\n\}\n)+Done pecl_http-3.0.1/tests/clientresponse003.phpt0000644000175000001440000000115712667772426017707 0ustar mikeusers--TEST-- client response transfer info --SKIPIF-- --FILE-- enqueue($request)->send()->getResponse(); var_dump($response->getTransferInfo("response_code")); var_dump(count((array)$response->getTransferInfo())); } }); ?> Done --EXPECTREGEX-- Test (?:int\([1-5]\d\d\) int\(\d\d\) )+Done pecl_http-3.0.1/tests/cookie001.phpt0000644000175000001440000000061412667772426016116 0ustar mikeusers--TEST-- cookies empty state --SKIPIF-- --FILE-- array(), "extras" => array(), "flags" => 0, "expires" => -1, "path" => "", "domain" => "", "max-age" => -1, ); var_dump($a == $c->toArray()); var_dump($a == $o->toArray()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/cookie002.phpt0000644000175000001440000000046712667772426016125 0ustar mikeusers--TEST-- cookies expire as date --SKIPIF-- --INI-- date.timezone=UTC --FILE-- $d->format(DateTime::RFC1123))); var_dump($d->format("U") == $c->getExpires()); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/cookie003.phpt0000644000175000001440000000037512667772426016124 0ustar mikeusers--TEST-- cookies numeric keys --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/cookie004.phpt0000644000175000001440000000042112667772426016115 0ustar mikeusers--TEST-- cookies raw --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/cookie005.phpt0000644000175000001440000000207412667772426016124 0ustar mikeusers--TEST-- cookies simple data --SKIPIF-- --FILE-- toArray()); foreach (array($orig, $copy) as $c) { var_dump($c->getCookie("key")); var_dump($c->getExpires()); var_dump($c->getMaxAge()); var_dump($c->getFlags()); var_dump($c->getPath()); var_dump($c->getDomain()); var_dump($c->getExtras()); var_dump($c->getCookies()); var_dump($c->toString()); var_dump( array ( "cookies" => array ( "key" => "value", ), "extras" => array ( ), "flags" => 0, "expires" => -1, "path" => "", "domain" => "", "max-age" => -1, ) == $c->toArray() ); } ?> DONE --EXPECT-- Test string(5) "value" int(-1) int(-1) int(0) NULL NULL array(0) { } array(1) { ["key"]=> string(5) "value" } string(11) "key=value; " bool(true) string(5) "value" int(-1) int(-1) int(0) NULL NULL array(0) { } array(1) { ["key"]=> string(5) "value" } string(11) "key=value; " bool(true) DONE pecl_http-3.0.1/tests/cookie006.phpt0000644000175000001440000000140412667772426016121 0ustar mikeusers--TEST-- cookies expire --SKIPIF-- --INI-- date.timezone=UTC --FILE-- getCookie("this")); var_dump($c->getExpires()); $o = clone $c; $t = time(); $o->setExpires(); var_dump(-1 === $o->getExpires()); var_dump(-1 != $c->getExpires()); $o->setExpires($t); var_dump($t === $o->getExpires()); var_dump($t != $c->getExpires()); var_dump( sprintf( "this=expires; expires=%s; ", date_create("@$t") ->setTimezone(new DateTimezone("UTC")) ->format("D, d M Y H:i:s \\G\\M\\T") ) === $o->toString() ); ?> DONE --EXPECT-- Test string(7) "expires" int(1327397732) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/cookie007.phpt0000644000175000001440000000111712667772426016123 0ustar mikeusers--TEST-- cookies max-age --SKIPIF-- --INI-- date.timezone=UTC --FILE-- getCookie("this")); var_dump($c->getMaxAge()); $o = clone $c; $t = 54321; $o->setMaxAge(); var_dump($o->getMaxAge()); var_dump(-1 != $c->getMaxAge()); $o->setMaxAge($t); var_dump($o->getMaxAge()); var_dump($t != $c->getMaxAge()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(7) "max-age" int(12345) int(-1) bool(true) int(54321) bool(true) string(29) "this=max-age; max-age=54321; " DONE pecl_http-3.0.1/tests/cookie008.phpt0000644000175000001440000000117412667772426016127 0ustar mikeusers--TEST-- cookies path --SKIPIF-- --FILE-- getCookie("this")); var_dump((string)$c); var_dump($c->getPath()); $o = clone $c; $p = "/up"; $o->setPath(); var_dump($o->getPath()); var_dump($c->getPath()); $o->setPath($p); var_dump($o->getPath()); var_dump($c->getPath()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(10) "has a path" string(33) "this=has%20a%20path; path=/down; " string(5) "/down" NULL string(5) "/down" string(3) "/up" string(5) "/down" string(31) "this=has%20a%20path; path=/up; " DONE pecl_http-3.0.1/tests/cookie009.phpt0000644000175000001440000000134512667772426016130 0ustar mikeusers--TEST-- cookies domain --SKIPIF-- --FILE-- getCookie("this")); var_dump((string)$c); var_dump($c->getDomain()); $o = clone $c; $d = "sub.example.com"; $o->setDomain(); var_dump($o->getDomain()); var_dump($c->getDomain()); $o->setDomain($d); var_dump($o->getDomain()); var_dump($c->getDomain()); var_dump($o->toString()); ?> DONE --EXPECT-- Test string(12) "has a domain" string(44) "this=has%20a%20domain; domain=.example.com; " string(12) ".example.com" NULL string(12) ".example.com" string(15) "sub.example.com" string(12) ".example.com" string(47) "this=has%20a%20domain; domain=sub.example.com; " DONE pecl_http-3.0.1/tests/cookie010.phpt0000644000175000001440000000164412667772426016122 0ustar mikeusers--TEST-- cookies flags --SKIPIF-- --FILE-- getFlags() & http\Cookie::SECURE)); var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY)); $c->setFlags($c->getFlags() ^ http\Cookie::SECURE); var_dump(!($c->getFlags() & http\Cookie::SECURE)); var_dump(http\Cookie::HTTPONLY === ($c->getFlags() & http\Cookie::HTTPONLY)); $c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY); var_dump(!($c->getFlags() & http\Cookie::SECURE)); var_dump(!($c->getFlags() & http\Cookie::HTTPONLY)); var_dump("icanhas=flags; " === $c->toString()); $c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY); var_dump("icanhas=flags; secure; httpOnly; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/cookie011.phpt0000644000175000001440000000213612667772426016120 0ustar mikeusers--TEST-- cookies extras --SKIPIF-- --FILE-- "v1", "c2"=>"v2") === $c->getCookies()); var_dump(array("e0"=>"1", "e2"=>"2") === $c->getExtras()); $c->addExtra("e1", 1); $c->setExtra("e0"); $c->setExtra("e3", 123); var_dump("123" === $c->getExtra("e3")); $c->setExtra("e3"); var_dump(array("e2"=>"2", "e1"=>"1") === $c->getExtras()); var_dump("c1=v1; c2=v2; e2=2; e1=1; " === $c->toString()); $c->addExtras(array("e3"=>3, "e4"=>4)); var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getExtras()); var_dump("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; " === $c->toString()); $c->setExtras(array("e"=>"x")); var_dump(array("e"=>"x") === $c->getExtras()); var_dump("c1=v1; c2=v2; e=x; " === $c->toString()); $c->setExtras(); var_dump(array() === $c->getExtras()); var_dump("c1=v1; c2=v2; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/cookie012.phpt0000644000175000001440000000215312667772426016120 0ustar mikeusers--TEST-- cookies cookies --SKIPIF-- --FILE-- "v1", "c2"=>"v2") === $c->getExtras()); var_dump(array("e0"=>"1", "e2"=>"2") === $c->getCookies()); $c->addCookie("e1", 1); $c->setCookie("e0"); $c->setCookie("e3", 123); var_dump("123" === $c->getCookie("e3")); $c->setCookie("e3"); var_dump(array("e2"=>"2", "e1"=>"1") === $c->getCookies()); var_dump("e2=2; e1=1; c1=v1; c2=v2; " === $c->toString()); $c->addCookies(array("e3"=>3, "e4"=>4)); var_dump(array("e2"=>"2", "e1"=>"1", "e3"=>"3", "e4"=>"4") === $c->getCookies()); var_dump("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; " === $c->toString()); $c->setCookies(array("e"=>"x")); var_dump(array("e"=>"x") === $c->getCookies()); var_dump("e=x; c1=v1; c2=v2; " === $c->toString()); $c->setCookies(); var_dump(array() === $c->getCookies()); var_dump("c1=v1; c2=v2; " === $c->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/encstream001.phpt0000644000175000001440000000061312667772426016625 0ustar mikeusers--TEST-- encoding stream chunked static --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/encstream002.phpt0000644000175000001440000000056012667772426016627 0ustar mikeusers--TEST-- encoding stream chunked not encoded --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Notice: http\Encoding\Stream\Dechunk::decode(): Data does not seem to be chunked encoded in %s on line %d bool(true) DONE pecl_http-3.0.1/tests/encstream003.phpt0000644000175000001440000000213012667772426016623 0ustar mikeusers--TEST-- encoding stream chunked error --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Warning: http\Encoding\Stream\Dechunk::decode(): Expected LF at pos 8 of 20 but got 0x74 in %s on line %d Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 11 at pos 9 of 20 in %s on line %d string(14) "is ter than 1 " Warning: http\Encoding\Stream\Dechunk::decode(): Expected CRLF at pos 10 of 24 but got 0x74 0x74 in %s on line %d Warning: http\Encoding\Stream\Dechunk::decode(): Truncated message: chunk size 190 exceeds remaining data size 12 at pos 12 of 24 in %s on line %d string(15) "is er than 1 " Warning: http\Encoding\Stream\Dechunk::decode(): Expected chunk size at pos 6 of 27 but got trash in %s on line %d bool(false) DONE pecl_http-3.0.1/tests/encstream004.phpt0000644000175000001440000000146112667772426016632 0ustar mikeusers--TEST-- encoding stream chunked flush --SKIPIF-- --FILE-- $line) { $dech = clone $dech; if ($i % 2) { $data .= $dech->update(sprintf("%lx\r\n%s\r\n", strlen($line), $line)); } else { $data .= $dech->update(sprintf("%lx\r\n", strlen($line))); $data .= $dech->flush(); $data .= $dech->update($line); $data .= $dech->flush(); $data .= $dech->update("\r\n"); } $dech->flush(); $dech->done() and printf("uh-oh done() reported true!\n"); } $data .= $dech->update("0\r\n"); var_dump($dech->done()); $data .= $dech->finish(); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/encstream005.phpt0000644000175000001440000000125312667772426016632 0ustar mikeusers--TEST-- encoding stream zlib static --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/encstream006.phpt0000644000175000001440000000110012667772426016622 0ustar mikeusers--TEST-- encoding stream zlib auto flush --SKIPIF-- --FILE-- update($defl->update($data))) { printf("uh-oh Β»%sΒ« != Β»%sΒ«\n", $data, $d); } } } echo $infl->update($defl->finish()); echo $infl->finish(); ?> DONE --EXPECT-- Test DONE pecl_http-3.0.1/tests/encstream007.phpt0000644000175000001440000000114612667772426016635 0ustar mikeusers--TEST-- encoding stream zlib without flush --SKIPIF-- --FILE-- update($line))) { foreach(str_split($temp) as $byte) { $data .= $infl->update($byte); } } } if (strlen($temp = $defl->finish())) { $data .= $infl->update($temp); } $data .= $infl->finish(); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/encstream008.phpt0000644000175000001440000000146412667772426016641 0ustar mikeusers--TEST-- encoding stream zlib with explicit flush --SKIPIF-- --FILE-- flush(); if (strlen($temp = $defl->update($line))) { $data .= $infl->update($temp); $data .= $infl->flush(); } if (strlen($temp = $defl->flush())) { $data .= $infl->update($temp); $data .= $infl->flush(); } $defl->done() or printf("uh-oh stream's not done yet!\n"); } if (strlen($temp = $defl->finish())) { $data .= $infl->update($temp); } var_dump($defl->done()); $data .= $infl->finish(); var_dump($infl->done()); var_dump(implode("", $file) === $data); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/encstream009.phpt0000644000175000001440000000054012667772426016634 0ustar mikeusers--TEST-- encoding stream zlib error --SKIPIF-- --FILE-- DONE --EXPECTF-- Test Warning: http\Encoding\Stream\Inflate::decode(): Could not inflate data: data error in %s on line %d bool(false) DONE pecl_http-3.0.1/tests/envrequestbody001.phpt0000644000175000001440000000031512667772426017722 0ustar mikeusers--TEST-- env request body --SKIPIF-- --PUT-- Content-Type: skip/me foo --FILE-- DONE --EXPECT-- string(3) "foo" DONE pecl_http-3.0.1/tests/envrequestcookie001.phpt0000644000175000001440000000070312667772426020237 0ustar mikeusers--TEST-- env request cookie --SKIPIF-- --COOKIE-- foo=bar;bar=123 --FILE-- getCookie()->toArray()); var_dump($r->getCookie("foo", "s")); var_dump($r->getCookie("bar", "i")); var_dump($r->getCookie("baz", "b", true)); ?> DONE --EXPECT-- Test array(2) { ["foo"]=> string(3) "bar" ["bar"]=> string(3) "123" } string(3) "bar" int(123) bool(true) DONE pecl_http-3.0.1/tests/envrequestfiles001.phpt0000644000175000001440000000125212667772426020070 0ustar mikeusers--TEST-- env request grabbing $_FILES --SKIPIF-- --POST_RAW-- Content-Type: multipart/form-data;boundary=--123 ----123 Content-Disposition: form-data;filename="foo.bar" foo bar ----123 Content-Disposition: form-data;filename="bar.foo" bar foo ----123-- --FILE-- getFiles(); foreach ($_FILES as $i => $file) { foreach (array("name","type","size","error","file") as $key) { if ($file[$key == "file" ? "tmp_name" : $key] != $f[$i][$key]) { printf("%d.%s differs: '%s' != '%s'\n", $i, $key, $f[$i][$key], $file[$key]); } } } ?> DONE --EXPECT-- TEST DONE pecl_http-3.0.1/tests/envrequestfiles002.phpt0000644000175000001440000000153512667772426020075 0ustar mikeusers--TEST-- env request grabbing $_FILES from array --SKIPIF-- --POST_RAW-- Content-Type: multipart/form-data;boundary=--123 ----123 Content-Disposition: form-data;filename=file1;name=file[] first ----123 Content-Disposition: form-data;filename=file2;name=file[] second ----123 Content-Disposition: form-data;filename=file3;name=file[] third ----123-- --FILE-- $data) { foreach ($data["tmp_name"] as $i => $file) { $f[$name][$i] = array( "file" => $file, "name" => $data["name"][$i], "size" => $data["size"][$i], "type" => $data["type"][$i], "error"=> $data["error"][$i] ); } } var_dump($f == $r->getFiles()); ?> DONE --EXPECT-- TEST bool(true) DONE pecl_http-3.0.1/tests/envrequestform.phpt0000644000175000001440000000062712667772426017515 0ustar mikeusers--TEST-- env request form --SKIPIF-- --POST-- a=b&b=c&r[]=1&r[]=2 --FILE-- getForm()); printf("%s\n", $r->getForm("b", "s", null, true)); printf("%s\n", $r->getForm("x", "s", "nooo")); printf("%s\n", $r->getForm()); ?> DONE --EXPECT-- TEST a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 c nooo a=b&r%5B0%5D=1&r%5B1%5D=2 DONE pecl_http-3.0.1/tests/envrequestheader001.phpt0000644000175000001440000000116712667772426020223 0ustar mikeusers--TEST-- env request header --SKIPIF-- --POST-- a=b --ENV-- HTTP_HOST=foo.bar HTTP_ACCEPT=*/* --FILE-- --EXPECTF-- NULL string(%d) "foo.bar" string(%d) "application/x-www-form-urlencoded" array(4) { ["Accept"]=> string(3) "*/*" ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(33) "application/x-www-form-urlencoded" ["Host"]=> string(7) "foo.bar" } pecl_http-3.0.1/tests/envrequestquery.phpt0000644000175000001440000000063312667772426017714 0ustar mikeusers--TEST-- env request query --SKIPIF-- --GET-- a=b&b=c&r[]=1&r[]=2 --FILE-- getQuery()); printf("%s\n", $r->getQuery("b", "s", null, true)); printf("%s\n", $r->getQuery("x", "s", "nooo")); printf("%s\n", $r->getQuery()); ?> DONE --EXPECT-- TEST a=b&b=c&r%5B0%5D=1&r%5B1%5D=2 c nooo a=b&r%5B0%5D=1&r%5B1%5D=2 DONE pecl_http-3.0.1/tests/envresponse001.phpt0000644000175000001440000000065712667772426017223 0ustar mikeusers--TEST-- env response message --SKIPIF-- --POST-- a=b --ENV-- HTTP_ACCEPT_ENCODING=gzip --FILE-- setHeader("foo","bar"); $r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); $r->setBody(new http\message\Body(fopen(__FILE__,"r"))); $r->send(); --EXPECTHEADERS-- Foo: bar Content-Encoding: gzip Vary: Accept-Encoding --EXPECTREGEX-- ^\x1f\x8b\x08.+ pecl_http-3.0.1/tests/envresponse002.phpt0000644000175000001440000000112712667772426017215 0ustar mikeusers--TEST-- env response cache negative --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT HTTP_IF_NONE_MATCH=0000-00-0000 --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send(); ?> --EXPECTHEADERS-- ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send(); ?> pecl_http-3.0.1/tests/envresponse003.phpt0000644000175000001440000000065712667772426017225 0ustar mikeusers--TEST-- env response ranges --SKIPIF-- --ENV-- HTTP_RANGE=bytes=2-4 --GET-- a=b --FILE-- setContentType("text/plain"); $r->setContentDisposition( array("attachment" => array(array("filename" => basename(__FILE__)))) ); $r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send(); ?> --EXPECTHEADERSF-- Content-Type: text/plain%s --EXPECTF-- php pecl_http-3.0.1/tests/envresponse004.phpt0000644000175000001440000000075312667772426017223 0ustar mikeusers--TEST-- env response callback --SKIPIF-- --GET-- dummy=1 --FILE-- setCacheControl("public,must-revalidate,max-age=0"); $r->setThrottleRate(1, 0.1); ob_start($r); echo "foo"; echo "bar"; ob_end_flush(); $r->send(); ?> --EXPECTHEADERS-- Accept-Ranges: bytes Cache-Control: public,must-revalidate,max-age=0 ETag: "9ef61f95" --EXPECTF-- foobar pecl_http-3.0.1/tests/envresponse005.phpt0000644000175000001440000000111112667772426017211 0ustar mikeusers--TEST-- env response cache positive --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:32 GMT --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); $r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); $r->send(); ?> --EXPECTHEADERS-- HTTP/1.1 304 Not Modified ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- pecl_http-3.0.1/tests/envresponse006.phpt0000644000175000001440000000065712667772426017230 0ustar mikeusers--TEST-- env response stream --SKIPIF-- --FILE-- addHeader("foo", array("bar","baz")); $r->getBody()->append("foo"); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> Done --EXPECT-- Test string(115) "HTTP/1.1 200 OK Accept-Ranges: bytes Foo: bar, baz ETag: "8c736521" Transfer-Encoding: chunked 3 foo 0 " Done pecl_http-3.0.1/tests/envresponse007.phpt0000644000175000001440000000121612667772426017221 0ustar mikeusers--TEST-- env response env request --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("Range", "bytes=2-4"); $res = new http\Env\Response; $res->setEnvRequest($req); $res->setContentType("text/plain"); $res->getBody()->append("012345679"); $res->send($tmp); rewind($tmp); var_dump(stream_get_contents($tmp)); ?> Done --EXPECTF-- Test string(%d) "HTTP/1.1 206 Partial Content%c Accept-Ranges: bytes%c X-Powered-By: %s%c Content-Type: text/plain%c Content-Range: bytes 2-4/9%c Transfer-Encoding: chunked%c %c 3%c 234%c 0%c %c " Done pecl_http-3.0.1/tests/envresponse008.phpt0000644000175000001440000000117712667772426017230 0ustar mikeusers--TEST-- env response stream message --SKIPIF-- --ENV-- HTTP_ACCEPT_ENCODING=gzip --FILE-- setHeader("foo","bar"); $r->setContentEncoding(http\env\Response::CONTENT_ENCODING_GZIP); $r->setBody(new http\message\Body(fopen(__FILE__,"r"))); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTREGEX-- string\(\d+\) "HTTP\/1\.1 200 OK Accept-Ranges: bytes Foo: bar Content-Encoding: gzip Vary: Accept-Encoding ETag: "\w+-\w+-\w+" Last-Modified: \w+, \d+ \w+ \d{4} \d\d:\d\d:\d\d GMT Transfer-Encoding: chunked d0 \x1f\x8b\x08.+ 0 " pecl_http-3.0.1/tests/envresponse009.phpt0000644000175000001440000000146212667772426017226 0ustar mikeusers--TEST-- env response stream cache negative --SKIPIF-- --GET-- a=b --ENV-- HTTP_IF_MODIFIED_SINCE=Fri, 13 Feb 2009 23:31:30 GMT HTTP_IF_NONE_MATCH=0000-00-0000 --FILE-- setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTF-- string(%d) "HTTP/1.1 200 OK%c Accept-Ranges: bytes%c X-Powered-By: %s%c ETag: "abc"%c Last-Modified: %s%c Transfer-Encoding: chunked%c %c e1%c setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> %c 0%c %c " pecl_http-3.0.1/tests/envresponse010.phpt0000644000175000001440000000121112667772426017206 0ustar mikeusers--TEST-- env response stream ranges --SKIPIF-- --ENV-- HTTP_RANGE=bytes=2-4 --GET-- a=b --FILE-- setContentType("text/plain"); $r->setContentDisposition( array("attachment" => array(array("filename" => basename(__FILE__)))) ); $r->setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send($f); rewind($f); var_dump(stream_get_contents($f)); ?> --EXPECTF-- string(%i) "HTTP/1.1 206 Partial Content%c Accept-Ranges: bytes%c X-Powered-By: PHP/%s%c Content-Type: text/plain%c Content-Range: bytes 2-4/311%c Transfer-Encoding: chunked%c %c 3%c php%c 0%c %c " pecl_http-3.0.1/tests/envresponse011.phpt0000644000175000001440000000123012667772426017210 0ustar mikeusers--TEST-- env response cache positive with env message --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("If-Modified-Since", "Fri, 13 Feb 2009 23:31:32 GMT"); $r = new http\Env\Response; $r->setEnvRequest($e); $r->setBody(new http\Message\Body(fopen(__FILE__,"rb"))); $r->setEtag("abc"); $r->setLastModified(1234567891); $r->isCachedByEtag("If-None-Match") and die("Huh? etag? really?\n"); $r->isCachedByLastModified("If-Modified-Since") or die("yep, I should be cached"); $r->send(); ?> --EXPECTHEADERS-- HTTP/1.1 304 Not Modified ETag: "abc" Last-Modified: Fri, 13 Feb 2009 23:31:31 GMT --EXPECT-- pecl_http-3.0.1/tests/envresponse012.phpt0000644000175000001440000000111512667772426017213 0ustar mikeusers--TEST-- env response content disposition --SKIPIF-- --GET-- dummy=1 --FILE-- setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); $r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); $r->send(); ?> --EXPECTHEADERS-- Content-Disposition: attachment;filename=envresponse012.php --EXPECT-- setContentDisposition(array("attachment"=>array("filename"=>basename(__FILE__)))); $r->setBody(new http\Message\Body(fopen(__FILE__,"r"))); $r->send(); ?> pecl_http-3.0.1/tests/envresponse013.phpt0000644000175000001440000000103112667772426017211 0ustar mikeusers--TEST-- env response deflate --SKIPIF-- --GET-- dummy=1 --FILE-- setHeader("Accept-Encoding", "deflate"); $res = new http\Env\Response; $res->setCacheControl("public, max-age=3600"); $res->setContentEncoding(http\Env\Response::CONTENT_ENCODING_GZIP); $res->getBody()->append("foobar"); $res->setEnvRequest($req); $res->send(); ?> --EXPECTHEADERS-- Content-Encoding: deflate Vary: Accept-Encoding Cache-Control: public, max-age=3600 --EXPECTREGEX-- ^\x78\x9c.+ pecl_http-3.0.1/tests/envresponse014.phpt0000644000175000001440000000075512667772426017226 0ustar mikeusers--TEST-- env response invalid ranges --SKIPIF-- --FILE-- setHeader("Range", "bytes=321-123,123-0"); $res = new http\Env\Response; $res->getBody()->append("foobar"); $res->setEnvRequest($req); $res->send($f); rewind($f); var_dump(stream_get_contents($f)); --EXPECTF-- string(129) "HTTP/1.1 416 Requested Range Not Satisfiable Accept-Ranges: bytes Content-Range: bytes */6 Transfer-Encoding: chunked 0 " pecl_http-3.0.1/tests/envresponse015.phpt0000644000175000001440000000100512667772426017214 0ustar mikeusers--TEST-- env response send replaced body using multiple ob_start --SKIPIF-- --FILE-- getBody(); $r->setBody(new http\Message\Body); ob_start($r); echo "foo: $b\n"; ob_end_flush(); $f = fopen("php://memory", "r+"); $r->send($f); fseek($f, 0, SEEK_SET); echo stream_get_contents($f); ?> --EXPECT-- HTTP/1.1 200 OK Accept-Ranges: bytes ETag: "fc8305a1" Transfer-Encoding: chunked 9 foo: bar 0 pecl_http-3.0.1/tests/envresponse016.phpt0000644000175000001440000000124012667772426017216 0ustar mikeusers--TEST-- env response send failure --SKIPIF-- --FILE-- getBody()->append(str_repeat("a", 16*1024*4)); $s = fopen("php://temp", "w"); stream_filter_append($s, "closer"); var_dump($r->send($s)); ?> DONE --EXPECTF-- Test Warning: http\Env\Response::send(): Failed to send response body in %s on line %d bool(false) DONE pecl_http-3.0.1/tests/envresponse017.phpt0000644000175000001440000000072012667772426017221 0ustar mikeusers--TEST-- env response stream: no chunked transfer encoding for CONNECTs --SKIPIF-- --FILE-- setRequestMethod("CONNECT"); $req->setRequestUrl(array("host"=>"www.example.com", "port"=>80)); echo $req; $res = new http\Env\Response; $res->setEnvRequest($req); $res->send(STDOUT); ?> ===DONE=== --EXPECTF-- Test CONNECT www.example.com:80 HTTP/1.1 HTTP/1.1 200 OK ===DONE=== pecl_http-3.0.1/tests/envresponse018.phpt0000644000175000001440000000071112667772426017222 0ustar mikeusers--TEST-- env response don't generate stat based etag for temp stream --SKIPIF-- --FILE-- append("1234567890\n"); $r = new http\Env\Response; $r->setBody($b); $r->send(STDOUT); ?> ===DONE=== --EXPECTF-- Test HTTP/1.1 200 OK Accept-Ranges: bytes ETag: "%x" Last-Modified: %s Transfer-Encoding: chunked b 1234567890 0 ===DONE=== pecl_http-3.0.1/tests/envresponsebody001.phpt0000644000175000001440000000035412667772426020073 0ustar mikeusers--TEST-- env response body --SKIPIF-- --INI-- output_buffering=1 --FILE-- getBody()); ?> Done --EXPECTF-- Test string(5) "Test " Done pecl_http-3.0.1/tests/envresponsebody002.phpt0000644000175000001440000000065512667772426020100 0ustar mikeusers--TEST-- env response body error --SKIPIF-- --INI-- output_buffering=1 --FILE-- getBody()); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> Done --EXPECTF-- Test http\Env\Response::__construct(): Could not fetch response body, output has already been sent at %senvresponsebody002.php:3 Done pecl_http-3.0.1/tests/envresponsecodes.phpt0000644000175000001440000000051312667772426020007 0ustar mikeusers--TEST-- env response codes --SKIPIF-- --FILE-- Done --EXPECT-- Test array(0) { } Done pecl_http-3.0.1/tests/envresponsecookie001.phpt0000644000175000001440000000063212667772426020406 0ustar mikeusers--TEST-- env response cookie --SKIPIF-- --FILE-- addCookie("foo","bar"); $c->setMaxAge(60); $r->setCookie($c); $r->setCookie("baz"); $r->setCookie(123); $r->send(STDOUT); ?> --EXPECT-- HTTP/1.1 200 OK Set-Cookie: foo=bar; max-age=60; Set-Cookie: baz=1; Set-Cookie: 123=1; ETag: "" Transfer-Encoding: chunked 0 pecl_http-3.0.1/tests/envresponseheader001.phpt0000644000175000001440000000137112667772426020366 0ustar mikeusers--TEST-- env response header --SKIPIF-- --FILE-- %s [Foo] => bar [More] => Array ( [0] => than [1] => what's [2] => good ) [Content-Type] => %s ) Created pecl_http-3.0.1/tests/envresponseranges001.phpt0000644000175000001440000000130212667772426020407 0ustar mikeusers--TEST-- ranges --SKIPIF-- --GET-- a=b --ENV-- HTTP_RANGE=bytes=-3,000-001,1-1,0-0,100- --FILE-- setBody(new http\Message\Body(fopen(__FILE__, "rb"))); $r->send(); ?> --EXPECTF-- --%s%c Content-Type: application/octet-stream%c Content-Range: bytes 107-109/110%c %c ?> %c --%s%c Content-Type: application/octet-stream%c Content-Range: bytes 0-1/110%c %c %c --%s--pecl_http-3.0.1/tests/etag001.phpt0000644000175000001440000000605512667772426015572 0ustar mikeusers--TEST-- etags with hash --SKIPIF-- --FILE-- append("Hello, my old fellow."); foreach (hash_algos() as $algo) { if (strncmp($algo, "sha3-", 5)) { ini_set("http.etag.mode", $algo); printf("%10s: %s\n", $algo, $body->etag() ); } } ?> DONE --EXPECT-- md2: 9bf7d8506d7453a85dc34fa730cbc16a md4: 137008b9144843f5bfcc6651688acc41 md5: 6ce3cc8f3861fb7fd0d77739f11cd29c sha1: ad84012eabe27a61762a97138d9d2623f4f1a7a9 sha224: 91be9bd30cec7fb7fb0279e40211fa71f8a7ab933f9f1a832d7c60cb sha256: ed9ecfe5c76d51179c3c1065916fdb8d94aee05577f187bd763cdc962bba1f42 sha384: 923a756152da113db192958da485c7881e7c4811d2d34e22f4d74cd45310d983f7fb1c5527a5f9037a4c7b649a6cc2b2 sha512: ad5ea693b8df4457d08d835ad5ccf7b626b66285f8424b3ec59e54c63bf63feef9a92baaba71c38d7bd9a1135488499fc835a8818390965c9ce8a5e4c40e519f ripemd128: b9e8d5864b5821d72e66101a9a0e730a ripemd160: d697a33676aece781b72f6fcb95f4c730367706b ripemd256: 9c3a73ab03e6d7d3471cf70316c4ff3ec56212d25730d382fb1480346529742b ripemd320: 5a6ee6b7c35c64d9c91019b9a1ceb2ab2ae19915f3dc96b0f244e15581d750a775a3682c5e70ee23 whirlpool: 2cb738084edaede8b36e9c8d81f5d30d9afe12bf60715073a6651c32c3448a6eeeff9f9715a8c996291ab3cd6c9a9caac8bea3b0eeb1c88afe6ad46fdd0cef83 tiger128,3: f3055bdb40b06abac716a27a654b295d tiger160,3: f3055bdb40b06abac716a27a654b295dc07e1ab9 tiger192,3: f3055bdb40b06abac716a27a654b295dc07e1ab915b56529 tiger128,4: e6a1628a4da8fa6adf4ca866c5e235b5 tiger160,4: e6a1628a4da8fa6adf4ca866c5e235b51939bb61 tiger192,4: e6a1628a4da8fa6adf4ca866c5e235b51939bb61ecf8423f snefru: 8f50c66c8f0a1510f9c591a2b7a070853d4770c60a38394c8857918dd91a2e5b snefru256: 8f50c66c8f0a1510f9c591a2b7a070853d4770c60a38394c8857918dd91a2e5b gost: efc79cdd01331adf80b30af816ff7a934f3f3df3085294a310918cacff3500f0 gost-crypto: 2e6bd37841520cc9ccb8c7abd68bd3ec9ce601651b995f3639090f585cc23684 adler32: 4ff5075d crc32: 757b06f7 crc32b: e56655c5 fnv132: ebd1fa1f fnv1a32: 8e2ee037 fnv164: 9790ce01eba3ae9f fnv1a64: 43ef200fe3ef9b37 joaat: 70a407c9 haval128,3: 68a1bee33d2a4fa5543be7fa871f84ea haval160,3: b4204e8c4f3c993385d997539afa723888700bbd haval192,3: 6c7f3442f5b5c7d338bd31ab9de1216576ce6633f8de9e03 haval224,3: 4edf7debeea48b94af73f47c1a4449dff516b69ba36f6659ed59689c haval256,3: eb919a27c9e598cf3559e79fca10119d54b6f704b779cd665ab5352eb17726c4 haval128,4: 184195034f2e5b2a0d04dcc42fac3275 haval160,4: b13d521378d7b74b226430355fa6f4ceba0782c2 haval192,4: 4e53f767e7dbff4abb8ebf767d672db3df77de7d9de6e9d9 haval224,4: 1208cc9fc1c23de3985f5a5214ebb67c846cecd32f96d950ef3ef770 haval256,4: 658d40b21f87ebe45cf6ec822402d1ca6965f263358e3927a92beba837785735 haval128,5: 938933eefe94e217d73a27909f89f8c6 haval160,5: 07b9e4a6c451acb5930081f414a06d948c1b70ba haval192,5: 997ca1515369b0051e9fcc736c1096618ef936f185a19ebe haval224,5: b46f2aada87d9e7a38b126268dce9779303aa4999d42f5c74427e362 haval256,5: 4e0b601e5ee93d6c2a449793e756e9ca6e03fb618c9f2ed849a7f8ca29ef9112 DONE pecl_http-3.0.1/tests/filterchunked.phpt0000644000175000001440000000111312667772426017246 0ustar mikeusers--TEST-- chunked filter --SKIPIF-- --FILE-- DONE --EXPECT-- DONE pecl_http-3.0.1/tests/filterzlib.phpt0000644000175000001440000000113312667772426016567 0ustar mikeusers--TEST-- zlib filter --SKIPIF-- --FILE-- DONE --EXPECT-- DONE pecl_http-3.0.1/tests/gh-issue6.phpt0000644000175000001440000000136112667772426016236 0ustar mikeusers--TEST-- url - unsafe characters --SKIPIF-- --FILE-- query; echo "\n"; echo (new http\Url("?id={\$id}"))->query; echo "\n"; ?> ===DONE=== --EXPECT-- Test __utma=1152894289.1017686999.9107388726.1439222726.1494721726.1&__utmb=115739289.1.10.1437388726&__utmc=115883619&__utmx=-&__utmz=115111289.14310476.1.1.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=(not%20provided)&__utmv=-&__utmk=112678937 id={$id} ===DONE=== pecl_http-3.0.1/tests/gh-issue7.phpt0000644000175000001440000000122012667772426016231 0ustar mikeusers--TEST-- crash with querystring and exception from error handler --SKIPIF-- =")) { die("skip PHP>=7\n"); } ?> --GET-- q[]=1&r[]=2 --FILE-- get("q","s")); } catch (\Exception $e) { echo $e->getMessage(),"\n"; } try { $r = new http\Env\Request; var_dump($r->getQuery("r", "s")); } catch (\Exception $e) { echo $e->getMessage(),"\n"; } ?> ===DONE=== --EXPECT-- Test Array to string conversion Array to string conversion ===DONE=== pecl_http-3.0.1/tests/gh-issue12.phpt0000644000175000001440000000120612667772426016311 0ustar mikeusers--TEST-- crash with bad url passed to http\Message::setRequestUrl() --SKIPIF-- --FILE-- setRequestUrl($url); printf("OK: %s\n", $url); } catch (Exception $e) { printf("%s\n", $e->getMessage()); } } ?> ===DONE=== --EXPECT-- Test http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar' http\Message::setRequestUrl(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar' OK: http://foo.bar. ===DONE=== pecl_http-3.0.1/tests/header001.phpt0000644000175000001440000000032512667772426016074 0ustar mikeusers--TEST-- header string --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/header002.phpt0000644000175000001440000000032212667772426016072 0ustar mikeusers--TEST-- header numeric --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/header003.phpt0000644000175000001440000000053112667772426016075 0ustar mikeusers--TEST-- header serialize --SKIPIF-- --FILE-- Done --EXPECT-- Test bool(true) bool(true) Done pecl_http-3.0.1/tests/header004.phpt0000644000175000001440000000141212667772426016075 0ustar mikeusers--TEST-- header match --SKIPIF-- --FILE-- match("gzip", http\Header::MATCH_WORD)); var_dump($ae->match("gzip", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); var_dump($ae->match("gzip", http\Header::MATCH_STRICT)); var_dump($ae->match("deflate", http\Header::MATCH_WORD)); var_dump($ae->match("deflate", http\Header::MATCH_WORD|http\Header::MATCH_CASE)); var_dump($ae->match("deflate", http\Header::MATCH_STRICT)); var_dump($ae->match("zip", http\Header::MATCH_WORD)); var_dump($ae->match("gzip", http\Header::MATCH_FULL)); ?> Done --EXPECT-- Test bool(true) bool(true) bool(false) bool(true) bool(true) bool(false) bool(false) bool(false) Done pecl_http-3.0.1/tests/header005.phpt0000644000175000001440000000130612667772426016100 0ustar mikeusers--TEST-- header negotiation --SKIPIF-- --FILE-- negotiate(array("text/plain","text/html"))); var_dump("text/html" === $a->negotiate(array("text/plain","text/html"), $rs)); var_dump(array("text/html"=>0.99, "text/plain"=>0.5) === $rs); var_dump("text/plain" === $a->negotiate(array("foo/bar", "text/plain"), $rs)); var_dump(array("text/plain"=>0.5) === $rs); var_dump("foo/bar" === $a->negotiate(array("foo/bar"), $rs)); var_dump(array() === $rs); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/header006.phpt0000644000175000001440000000074712667772426016111 0ustar mikeusers--TEST-- header parsing --SKIPIF-- --FILE-- "bar","Bar"=>"foo") === http\Header::parse($header)); $headers = http\Header::parse($header, "http\\Header"); var_dump(2 === count($headers)); var_dump(2 === array_reduce($headers, function($count, $header) { return $count + ($header instanceof http\Header); }, 0)); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/header007.phpt0000644000175000001440000000046112667772426016103 0ustar mikeusers--TEST-- header parse error --SKIPIF-- --FILE-- Done --EXPECTF-- Test Warning: http\Header::parse(): Failed to parse headers: unexpected end of line at pos 4 of 'wass\nup' in %s on line %d Done pecl_http-3.0.1/tests/header008.phpt0000644000175000001440000000073112667772426016104 0ustar mikeusers--TEST-- header params --SKIPIF-- --FILE-- array("value" => true, "arguments" => array()), "must-revalidate" => array("value" => true, "arguments" => array()), "max-age" => array("value" => "0", "arguments" => array()), ) === $header->getParams()->params ); ?> Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/header009.phpt0000644000175000001440000000071212667772426016104 0ustar mikeusers--TEST-- header params w/ args --SKIPIF-- --FILE-- array("value" => "bar", "arguments" => array()), "bar" => array("value" => "bis", "arguments" => array("bis" => "where")) ) === $header->getParams(".", "where", "is")->params ); ?> Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/headerparser001.phpt0000644000175000001440000000265112667772426017315 0ustar mikeusers--TEST-- header parser --SKIPIF-- --FILE-- "FAILURE",0=>"START","KEY","VALUE","VALUE_EX","HEADER_DONE","DONE"); $parser = new http\Header\Parser; do { $state = $parser->parse($part = array_shift($headers), $headers ? 0 : http\Header\Parser::CLEANUP, $result); printf("%2\$-32s | %1\$s\n", $states[$state], addcslashes($part, "\r\n\t\0")); } while ($headers && $state !== http\Header\Parser::STATE_FAILURE); var_dump($result); ?> ===DONE=== --EXPECT-- Test One: | VALUE header\n | VALUE_EX Two: header\n\tlines\n | VALUE_EX Three | KEY : header\n lines\n here\n | VALUE_EX More: than one header\n | VALUE_EX More: | VALUE than: | VALUE you: | VALUE expect\n | VALUE_EX \n | DONE array(4) { ["One"]=> string(6) "header" ["Two"]=> string(12) "header lines" ["Three"]=> string(17) "header lines here" ["More"]=> array(2) { [0]=> string(15) "than one header" [1]=> string(17) "than: you: expect" } } ===DONE=== pecl_http-3.0.1/tests/headerparser002.phpt0000644000175000001440000000267712667772426017326 0ustar mikeusers--TEST-- header parser errors --SKIPIF-- --FILE-- parse($header, http\Header\Parser::CLEANUP, $parsed), $parsed); } ?> ===DONE=== --EXPECTF-- Test Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 2 of 'Na\000me' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected end of line at pos 2 of 'Na\nme: value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 0 of '\000value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected end of input at pos 5 of 'value' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 3 of 'val\000ue' in %sheaderparser002.php on line %d int(-1) array(0) { } Warning: http\Header\Parser::parse(): Failed to parse headers: unexpected character '\000' at pos 5 of 'value\000' in %sheaderparser002.php on line %d int(-1) array(0) { } ===DONE===pecl_http-3.0.1/tests/headerparser003.phpt0000644000175000001440000000143712667772426017320 0ustar mikeusers--TEST-- header parser with nonblocking stream --SKIPIF-- --FILE-- stream($socket[0], 0, $hdrs); fwrite($socket[1], $line); var_dump($parser->getState()); var_dump($parser->stream($socket[0], 0, $hdrs)); } var_dump($hdrs); ?> DONE --EXPECT-- Test int(0) int(1) int(1) int(2) int(2) int(3) int(3) int(1) int(1) int(3) int(3) int(5) array(2) { ["Host"]=> string(9) "localhost" ["Content-Length"]=> string(1) "3" } DONE pecl_http-3.0.1/tests/info001.phpt0000644000175000001440000000277712667772426015614 0ustar mikeusers--TEST-- invalid HTTP info --SKIPIF-- --FILE-- DONE --EXPECTF-- http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 3 of 'GET HTTP/1.1' in %s Stack trace: #0 %s: http\Message->__construct('GET HTTP/1.1') #1 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 3 of 'GET HTTP/1.123' in %s Stack trace: #0 %s: http\Message->__construct('GET HTTP/1.123') #1 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\057' at pos 7 of 'GETHTTP/1.1' %s Stack trace: #0 %s: http\Message->__construct('GETHTTP/1.1') #1 {main} object(http\Message)#%d (9) { ["type":protected]=> int(1) ["body":protected]=> NULL ["requestMethod":protected]=> string(3) "GET" ["requestUrl":protected]=> string(1) "/" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(0) { } ["parentMessage":protected]=> NULL } DONE pecl_http-3.0.1/tests/info002.phpt0000644000175000001440000000230712667772426015602 0ustar mikeusers--TEST-- invalid HTTP info --SKIPIF-- --FILE-- ===DONE=== --EXPECTF-- Test http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\057' at pos 4 of 'HTTP/1.1 99 Apples in my Basket' in %sinfo002.php:%d Stack trace: #0 %sinfo002.php(%d): http\Message->__construct('HTTP/1.1 99 App...') #1 %sinfo002.php(%d): {closure}() #2 %sinfo002.php(%d): trap(Object(Closure)) #3 {main} http\Exception\BadMessageException: http\Message::__construct(): Failed to parse headers: unexpected character '\040' at pos 7 of 'CONNECT HTTP/1.1' in %sinfo002.php:%d Stack trace: #0 %sinfo002.php(%d): http\Message->__construct('CONNECT HTTP/1....') #1 %sinfo002.php(%d): {closure}() #2 %sinfo002.php(%d): trap(Object(Closure)) #3 {main} HTTP/1.1 200 CONNECT www.example.org:80 HTTP/1.1 ===DONE=== pecl_http-3.0.1/tests/message001.phpt0000644000175000001440000002443412667772426016277 0ustar mikeusers--TEST-- message --SKIPIF-- --FILE-- getHttpVersion(), $m->getType()==HttpMessage::TYPE_NONE, $m->getHeaders() ); $m = new HttpMessage("GET / HTTP/1.1\r\n"); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_REQUEST, $m->getRequestMethod(), $m->getRequestUrl(), $m->getHeaders() ); $m = new HttpMessage("HTTP/1.1 200 Okidoki\r\n"); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo "---\n"; $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_gzip.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_empty_chunked.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(file_get_contents(__DIR__."/data/message_rr_helloworld_chunked.txt")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); echo "---\n"; $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_gzip.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_empty_chunked.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); $m = new HttpMessage(fopen(__DIR__."/data/message_rr_helloworld_chunked.txt", "r+b")); echo $m; var_dump( $m->getHttpVersion(), $m->getType()==HttpMessage::TYPE_RESPONSE, $m->getResponseCode(), $m->getResponseStatus(), $m->getHeaders() ); echo $m->getParentMessage(); echo "Done\n"; --EXPECTF-- Test string(3) "1.1" bool(true) array(0) { } GET / HTTP/1.1 string(3) "1.1" bool(true) string(3) "GET" string(1) "/" array(0) { } HTTP/1.1 200 Okidoki string(3) "1.1" bool(true) int(200) string(7) "Okidoki" array(0) { } --- 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 X-Original-Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Wed, 25 Aug 2010 12:11:44 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Content-Length"]=> string(1) "0" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(1) "0" } GET /default/empty.txt HTTP/1.1 Host: localhost 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 Connection: close Content-Type: text/plain X-Original-Content-Length: 20 X-Original-Content-Encoding: gzip string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Thu, 26 Aug 2010 09:55:09 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(2) "20" ["X-Original-Content-Encoding"]=> string(4) "gzip" } GET /default/empty.txt HTTP/1.1 Host: localhost Accept-Encoding: gzip Connection: close 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 Content-Type: text/html X-Original-Transfer-Encoding: chunked Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(8) { ["Date"]=> string(29) "Thu, 26 Aug 2010 11:41:02 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["X-Powered-By"]=> string(9) "PHP/5.3.3" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(9) "text/html" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(0) } GET /default/empty.php HTTP/1.1 Connection: close Host: localhost 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 Content-Type: text/plain X-Original-Transfer-Encoding: chunked Content-Length: 14 Hello, World! string(3) "1.1" bool(true) int(200) string(2) "OK" array(7) { ["Date"]=> string(29) "Thu, 26 Aug 2010 12:51:28 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(14) } GET /cgi-bin/chunked.sh 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 X-Original-Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Wed, 25 Aug 2010 12:11:44 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Content-Length"]=> string(1) "0" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(1) "0" } GET /default/empty.txt HTTP/1.1 Host: localhost 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 Connection: close Content-Type: text/plain X-Original-Content-Length: 20 X-Original-Content-Encoding: gzip string(3) "1.1" bool(true) int(200) string(2) "OK" array(10) { ["Date"]=> string(29) "Thu, 26 Aug 2010 09:55:09 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Last-Modified"]=> string(29) "Wed, 28 Apr 2010 10:54:37 GMT" ["Etag"]=> string(23) ""2002a-0-48549d615a35c"" ["Accept-Ranges"]=> string(5) "bytes" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Content-Length"]=> string(2) "20" ["X-Original-Content-Encoding"]=> string(4) "gzip" } GET /default/empty.txt HTTP/1.1 Host: localhost Accept-Encoding: gzip Connection: close 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 Content-Type: text/html X-Original-Transfer-Encoding: chunked Content-Length: 0 string(3) "1.1" bool(true) int(200) string(2) "OK" array(8) { ["Date"]=> string(29) "Thu, 26 Aug 2010 11:41:02 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["X-Powered-By"]=> string(9) "PHP/5.3.3" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(9) "text/html" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(0) } GET /default/empty.php HTTP/1.1 Connection: close Host: localhost 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 Content-Type: text/plain X-Original-Transfer-Encoding: chunked Content-Length: 14 Hello, World! string(3) "1.1" bool(true) int(200) string(2) "OK" array(7) { ["Date"]=> string(29) "Thu, 26 Aug 2010 12:51:28 GMT" ["Server"]=> string(68) "Apache/2.2.16 (Unix) mod_ssl/2.2.16 OpenSSL/1.0.0a mod_fastcgi/2.4.6" ["Vary"]=> string(15) "Accept-Encoding" ["Connection"]=> string(5) "close" ["Content-Type"]=> string(10) "text/plain" ["X-Original-Transfer-Encoding"]=> string(7) "chunked" ["Content-Length"]=> int(14) } GET /cgi-bin/chunked.sh HTTP/1.1 Host: localhost Connection: close Done pecl_http-3.0.1/tests/message002.phpt0000644000175000001440000000346712667772426016303 0ustar mikeusers--TEST-- env request message --SKIPIF-- --POST_RAW-- Content-Type: test/something b=c --ENV-- HTTP_X_TEST=test --COOKIE-- foo=bar --INI-- always_populate_raw_post_data=-1 --FILE-- getHeaders(); ksort($h); $m->setHeaders($h); var_dump($m); echo "Message->toString\n"; echo $m,"\n"; echo "Body->toString\n"; var_dump((string)$m->getBody()); echo "stream\n"; var_dump(file_get_contents("php://input")); ?> Done --EXPECTF-- Test object(%s)#%d (13) { ["type":protected]=> int(1) ["body":protected]=> NULL ["requestMethod":protected]=> string(4) "POST" ["requestUrl":protected]=> string(0) "" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(4) { ["Content-Length"]=> string(1) "3" ["Content-Type"]=> string(14) "test/something" ["Cookie"]=> string(7) "foo=bar" ["X-Test"]=> string(4) "test" } ["parentMessage":protected]=> NULL ["query":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(0) { } } ["form":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(0) { } } ["cookie":protected]=> object(http\QueryString)#%d (1) { ["queryArray":"http\QueryString":private]=> array(1) { ["foo"]=> string(3) "bar" } } ["files":protected]=> array(0) { } } Message->toString POST / HTTP/1.1%a Content-Length: 3%a Content-Type: test/something%a Cookie: foo=bar%a X-Test: test%a %a b=c Body->toString string(3) "b=c" stream string(3) "b=c" Done pecl_http-3.0.1/tests/message003.phpt0000644000175000001440000000505712667772426016301 0ustar mikeusers--TEST-- multipart message --SKIPIF-- --FILE-- isMultipart($boundary)) { var_dump($boundary); foreach ($m->splitMultipartBody() as $i => $mm) { echo "==$i==\n",$mm,"===\n"; } } ?> DONE --EXPECTF-- string(40) "----------------------------6e182425881c" ==%d== Content-Disposition: form-data; name="composer"; filename="composer.json" Content-Type: application/octet-stream Content-Length: 567 { "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" } } } === ==%d== Content-Disposition: form-data; name="LICENSE"; filename="LICENSE" Content-Type: application/octet-stream Content-Length: 1354 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. === DONE pecl_http-3.0.1/tests/message004.phpt0000644000175000001440000000172012667772426016273 0ustar mikeusers--TEST-- message reversal --SKIPIF-- --FILE-- toString(true); echo "===\n"; echo newHttpMessage($s)->reverse()->toString(true); $m = newHttpMessage($s); $r = $m->reverse(); unset($m); var_dump($r->count()); echo $r->toString(true); ?> DONE --EXPECTF-- GET /first HTTP/1.1 HTTP/1.1 200 Ok-first GET /second HTTP/1.1 HTTP/1.1 200 Ok-second GET /third HTTP/1.1 HTTP/1.1 200 Ok-third === HTTP/1.1 200 Ok-third GET /third HTTP/1.1 HTTP/1.1 200 Ok-second GET /second HTTP/1.1 HTTP/1.1 200 Ok-first GET /first HTTP/1.1 int(6) HTTP/1.1 200 Ok-third GET /third HTTP/1.1 HTTP/1.1 200 Ok-second GET /second HTTP/1.1 HTTP/1.1 200 Ok-first GET /first HTTP/1.1 DONE pecl_http-3.0.1/tests/message005.phpt0000644000175000001440000000065012667772426016275 0ustar mikeusers--TEST-- message cloning --SKIPIF-- setType(http\Message::TYPE_REQUEST); $cpy->setHeaders(array("Numbers" => array(1,2,3,4.5))); echo $msg; echo "\n===\n"; echo $cpy; ?> DONE --EXPECTF-- HTTP/1.1 200 Ok String: foobar === UNKNOWN / HTTP/1.1 Numbers: 1, 2, 3, 4.5 DONE pecl_http-3.0.1/tests/message006.phpt0000644000175000001440000000130112667772426016270 0ustar mikeusers--TEST-- message var_dump with inherited property with increased access level --SKIPIF-- --FILE-- headers["foo"] = "bar"; var_dump($m); ?> DONE --EXPECTF-- Test object(c)#%d (9) { ["headers"]=> array(1) { ["foo"]=> string(3) "bar" } ["type":protected]=> int(0) ["body":protected]=> NULL ["requestMethod":protected]=> string(0) "" ["requestUrl":protected]=> string(0) "" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["parentMessage":protected]=> NULL } DONE pecl_http-3.0.1/tests/message007.phpt0000644000175000001440000000060112667772426016273 0ustar mikeusers--TEST-- message to stream --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $m->getBody()->append("this\nis\nthe\ntext"); $f = tmpfile(); $m->toStream($f); rewind($f); var_dump((string) $m === stream_get_contents($f)); fclose($f); ?> Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/message008.phpt0000644000175000001440000000075712667772426016310 0ustar mikeusers--TEST-- message to callback --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $m->getBody()->append("this\nis\nthe\ntext"); $d = new http\Encoding\Stream\Deflate; $s = ""; $m->toCallback(function ($m, $data) use ($d, &$s) { $s.=$d->update($data); }); $s.=$d->finish(); var_dump($m->toString() === http\Encoding\Stream\Inflate::decode($s)); ?> Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/message009.phpt0000644000175000001440000000772512667772426016313 0ustar mikeusers--TEST-- message properties --SKIPIF-- --FILE-- $prop; case "set": $this->$prop = current($args); break; } } } } $test = new message; var_dump(0 === $test->testGetType()); var_dump(null === $test->testGetBody()); var_dump(null === $test->testGetRequestMethod()); var_dump(null === $test->testGetRequestUrl()); var_dump(null === $test->testGetResponseStatus()); var_dump(null === $test->testGetResponseCode()); var_dump("1.1" === $test->testGetHttpVersion()); var_dump(array() === $test->testGetHeaders()); var_dump(null === $test->testGetParentMessage()); $test->testSetType(http\Message::TYPE_REQUEST); var_dump(http\Message::TYPE_REQUEST === $test->testGetType()); var_dump(http\Message::TYPE_REQUEST === $test->getType()); $body = new http\Message\Body; $test->testSetBody($body); var_dump($body === $test->testGetBody()); var_dump($body === $test->getBody()); $file = fopen(__FILE__,"r"); $test->testSetBody($file); var_dump($file === $test->testGetBody()->getResource()); var_dump($file === $test->getBody()->getResource()); $test->testSetBody("data"); var_dump("data" === (string) $test->testGetBody()); var_dump("data" === (string) $test->getBody()); $test->testSetRequestMethod("HEAD"); var_dump("HEAD" === $test->testGetRequestMethod()); var_dump("HEAD" === $test->getRequestMethod()); $test->testSetRequestUrl("/"); var_dump("/" === $test->testGetRequestUrl()); var_dump("/" === $test->getRequestUrl()); var_dump("HEAD / HTTP/1.1" === $test->getInfo()); $test->testSetType(http\Message::TYPE_RESPONSE); $test->setResponseStatus("Created"); var_dump("Created" === $test->testGetResponseStatus()); var_dump("Created" === $test->getResponseStatus()); $test->setResponseCode(201); var_dump(201 === $test->testGetResponseCode()); var_dump(201 === $test->getResponseCode()); $test->testSetResponseStatus("Ok"); var_dump("Ok" === $test->testGetResponseStatus()); var_dump("Ok" === $test->getResponseStatus()); $test->testSetResponseCode(200); var_dump(200 === $test->testGetResponseCode()); var_dump(200 === $test->getResponseCode()); $test->testSetHttpVersion("1.0"); var_dump("1.0" === $test->testGetHttpVersion()); var_dump("1.0" === $test->getHttpVersion()); var_dump("HTTP/1.0 200 OK" === $test->getInfo()); $test->setHttpVersion("1.1"); var_dump("1.1" === $test->testGetHttpVersion()); var_dump("1.1" === $test->getHttpVersion()); var_dump("HTTP/1.1 200 OK" === $test->getInfo()); $test->setInfo("HTTP/1.1 201 Created"); var_dump("Created" === $test->testGetResponseStatus()); var_dump("Created" === $test->getResponseStatus()); var_dump(201 === $test->testGetResponseCode()); var_dump(201 === $test->getResponseCode()); var_dump("1.1" === $test->testGetHttpVersion()); var_dump("1.1" === $test->getHttpVersion()); $test->testSetHeaders(array("Foo" => "bar")); var_dump(array("Foo" => "bar") === $test->testGetHeaders()); var_dump(array("Foo" => "bar") === $test->getHeaders()); var_dump("bar" === $test->getHeader("foo")); var_dump(false === $test->getHeader("bar")); $parent = new message; $test->testSetParentMessage($parent); var_dump($parent === $test->testGetParentMessage()); var_dump($parent === $test->getParentMessage()); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/message010.phpt0000644000175000001440000000054112667772426016270 0ustar mikeusers--TEST-- message body --SKIPIF-- --FILE-- append("foo"); $m->addBody($body); $body = new http\Message\Body; $body->append("bar"); $m->addBody($body); var_dump("foobar" === (string) $m->getBody()); ?> Done --EXPECT-- Test bool(true) Done pecl_http-3.0.1/tests/message011.phpt0000644000175000001440000000321012667772426016265 0ustar mikeusers--TEST-- message headers --SKIPIF-- --INI-- date.timezone=UTC --FILE-- str = $str; } function __toString() { return (string) $this->str; } } $m = new http\Message; $m->addHeaders(array("foo"=>"bar","bar"=>"foo")); var_dump(array("Foo"=>"bar", "Bar"=>"foo") === $m->getHeaders()); $m->addHeaders(array("key"=>"val","more"=>"Stuff")); var_dump(array("Foo"=>"bar", "Bar"=>"foo","Key"=>"val","More"=>"Stuff") === $m->getHeaders()); $m = new http\Message("GET / HTTP/1.1"); $m->addHeader("Accept", "text/html"); $m->addHeader("Accept", "text/xml;q=0"); $m->addHeader("Accept", "text/plain;q=0.5"); var_dump( "GET / HTTP/1.1\r\n". "Accept: text/html, text/xml;q=0, text/plain;q=0.5\r\n" === $m->toString() ); $m = new http\Message("HTTP/1.1 200 Ok"); $m->addHeader("Bool", true); $m->addHeader("Int", 123); $m->addHeader("Float", 1.23); $m->addHeader("Array", array(1,2,3)); $m->addHeader("Object", new strval("test")); $m->addHeader("Set-Cookie", array( array( "cookies" => array("foo" => "bar"), "expires" => date_create("2012-12-31 22:59:59 GMT")->format( DateTime::COOKIE ), "path" => "/somewhere" ) ) ); $m->addHeader("Set-Cookie", "val=0"); var_dump( "HTTP/1.1 200 Ok\r\n". "Bool: true\r\n". "Int: 123\r\n". "Float: 1.23\r\n". "Array: 1, 2, 3\r\n". "Object: test\r\n". "Set-Cookie: foo=bar; path=/somewhere; expires=Mon, 31 Dec 2012 22:59:59 GMT; \r\n". "Set-Cookie: val=0\r\n" === $m->toString() ); ?> Done --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/message012.phpt0000644000175000001440000000071012667772426016270 0ustar mikeusers--TEST-- message part --SKIPIF-- --FILE-- addHeader("Content-Type", "text/plain"); $p->getBody()->append("data"); $m = new http\Message("HTTP/1.1 200"); $m->getBody()->addPart($p); echo $m; ?> Done --EXPECTF-- Test HTTP/1.1 200 Content-Length: %d Content-Type: multipart/form-data; boundary="%x.%x" --%x.%x Content-Type: text/plain Content-Length: 4 data --%x.%x-- Done pecl_http-3.0.1/tests/message013.phpt0000644000175000001440000000067112667772426016277 0ustar mikeusers--TEST-- message detach --SKIPIF-- --FILE-- detach(); var_dump(3 === count($m)); var_dump(1 === count($d)); var_dump("HTTP/1.1 302 Found\r\n\r\n" === $d->toString(true)); ?> Done --EXPECTF-- Test bool(true) bool(true) bool(true) bool(true) Done pecl_http-3.0.1/tests/message014.phpt0000644000175000001440000000104112667772426016270 0ustar mikeusers--TEST-- message prepend --SKIPIF-- --FILE-- prepend($p); $p = $m; } var_dump( "HTTP/1.1 200\r\n\r\n". "HTTP/1.1 201\r\n\r\n". "HTTP/1.1 202\r\n\r\n". "HTTP/1.1 203\r\n\r\n". "HTTP/1.1 204\r\n\r\n". "HTTP/1.1 205\r\n\r\n". "HTTP/1.1 206\r\n\r\n". "HTTP/1.1 207\r\n\r\n". "HTTP/1.1 208\r\n\r\n" === $m->toString(true) ); ?> Done --EXPECTF-- Test bool(true) Done pecl_http-3.0.1/tests/message015.phpt0000644000175000001440000000156612667772426016305 0ustar mikeusers--TEST-- message errors --SKIPIF-- --FILE-- setRequestUrl("/foo"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m->setType(http\Message::TYPE_REQUEST); try { $m->setRequestUrl(""); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m = new http\Message; try { $m->getParentMessage(); die("unreached"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } $m = new http\Message("HTTP/1.1 200\r\nHTTP/1.1 201"); try { $m->prepend($m->getParentMessage()); die("unreached"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> Done --EXPECTF-- Test http\Message is not of type request Cannot set http\Message's request url to an empty string http\Message has not parent message Cannot prepend a message located within the same message chain Done pecl_http-3.0.1/tests/message016.phpt0000644000175000001440000000066412667772426016304 0ustar mikeusers--TEST-- message content range --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test 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 X-Original-Content-Length: 3 23===DONE=== pecl_http-3.0.1/tests/messagebody001.phpt0000644000175000001440000000113512667772426017146 0ustar mikeusers--TEST-- message body stat --SKIPIF-- --FILE-- stat("size")); var_dump(filemtime(__FILE__) === $file->stat("mtime")); var_dump(fileatime(__FILE__) === $file->stat("atime")); var_dump(filectime(__FILE__) === $file->stat("ctime")); var_dump( (object) array( "size" => 0, "mtime" => 0, "atime" => 0, "ctime" => 0, ) == $temp->stat() ); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/messagebody002.phpt0000644000175000001440000000034612667772426017152 0ustar mikeusers--TEST-- message body append --SKIPIF-- --FILE-- append("yes"); var_dump((string) $temp); ?> DONE --EXPECT-- Test string(3) "yes" DONE pecl_http-3.0.1/tests/messagebody003.phpt0000644000175000001440000000067612667772426017161 0ustar mikeusers--TEST-- message body append error --SKIPIF-- --FILE-- append("nope"); } catch (Exception $e) { echo $e, "\n"; } ?> DONE --EXPECTF-- Test http\Exception\RuntimeException: http\Message\Body::append(): Failed to append 4 bytes to body; wrote 0 in %s:%d Stack trace: #0 %s(%d): http\Message\Body->append('nope') #1 {main} DONE pecl_http-3.0.1/tests/messagebody004.phpt0000644000175000001440000000177012667772426017156 0ustar mikeusers--TEST-- message body add form --SKIPIF-- --FILE-- addForm( array( "foo" => "bar", "more" => array( "bah", "baz", "fuz" ), ), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ) ) ); echo $temp; ?> DONE --EXPECTF-- Test --%x.%x Content-Disposition: form-data; name="foo" bar --%x.%x Content-Disposition: form-data; name="more[0]" bah --%x.%x Content-Disposition: form-data; name="more[1]" baz --%x.%x Content-Disposition: form-data; name="more[2]" fuz --%x.%x Content-Disposition: form-data; name="upload"; filename="%s" Content-Transfer-Encoding: binary Content-Type: text/plain addForm( array( "foo" => "bar", "more" => array( "bah", "baz", "fuz" ), ), array( array( "file" => __FILE__, "name" => "upload", "type" => "text/plain", ) ) ); echo $temp; ?> DONE --%x.%x-- DONE pecl_http-3.0.1/tests/messagebody005.phpt0000644000175000001440000000065112667772426017154 0ustar mikeusers--TEST-- message body add part --SKIPIF-- --FILE-- getBoundary()); $temp->addPart(new http\Message("This: is a header\n\nand this is the data\n")); var_dump($temp->getBoundary()); echo $temp; ?> DONE --EXPECTF-- Test NULL string(%d) "%x.%x" --%x.%x This: is a header Content-Length: 21 and this is the data --%x.%x-- DONE pecl_http-3.0.1/tests/messagebody006.phpt0000644000175000001440000000064512667772426017160 0ustar mikeusers--TEST-- message body etag --SKIPIF-- --INI-- http.etag.mode = crc32b --FILE-- etag() ); var_dump($temp->etag()); ?> DONE --EXPECT-- Test bool(true) string(8) "00000000" DONE pecl_http-3.0.1/tests/messagebody007.phpt0000644000175000001440000000052212667772426017153 0ustar mikeusers--TEST-- message body to stream --SKIPIF-- --FILE-- toStream($f = fopen("php://temp", "w")); fseek($f, 0, SEEK_SET); var_dump(file_get_contents(__FILE__) === stream_get_contents($f)); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/messagebody008.phpt0000644000175000001440000000047512667772426017163 0ustar mikeusers--TEST-- message body to callback --SKIPIF-- --FILE-- toCallback( function($body, $string) use (&$s) { $s.=$string; } ); var_dump($s === (string) $file); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/messagebody009.phpt0000644000175000001440000000036512667772426017162 0ustar mikeusers--TEST-- message body clone --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/messagebody010.phpt0000644000175000001440000000055512667772426017153 0ustar mikeusers--TEST-- message body resource --SKIPIF-- --FILE-- getResource(); var_dump(is_resource($stream)); $stat = fstat($stream); var_dump(filesize(__FILE__) === $stat["size"]); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/messageparser001.phpt0000644000175000001440000000252412667772426017510 0ustar mikeusers--TEST-- message parser --SKIPIF-- --FILE-- parse(fgets($fd), 0, $message)) { case Parser::STATE_DONE: $string = (string) $message; break 2; case Parser::STATE_FAILURE: throw new Exception(($e = error_get_last()) ? $e["message"] : "Could not parse $file"); } } if (!$string) { $s = array("START", "HEADER", "HEADER_DONE", "BODY", "BODY_DUMB", "BODY_LENGTH", "BODY_CHUNK", "BODY_DONE", "UPDATE_CL", "DONE"); printf("Unexpected state: %s (%s)\n", $s[$parser->getState()], $file); } $parser = new Parser; rewind($fd); unset($message); switch ($parser->stream($fd, 0, $message)) { case Parser::STATE_DONE: case Parser::STATE_START: break; default: printf("Expected parser state 0 or 8, got %d", $parser->getState()); } if ($string !== (string) $message) { $a = explode("\n", $string); $b = explode("\n", (string) $message); do { $aa = array_shift($a); $bb = array_shift($b); if ($aa !== $bb) { isset($aa) and printf("-- %s\n", $aa); isset($bb) and printf("++ %s\n", $bb); } } while ($a || $b); } } ?> DONE --EXPECT-- Test DONE pecl_http-3.0.1/tests/messageparser002.phpt0000644000175000001440000000226712667772426017515 0ustar mikeusers--TEST-- message parser with nonblocking stream --SKIPIF-- --FILE-- stream($socket[0], 0, $msg); fwrite($socket[1], $line); $parser->stream($socket[0], 0, $msg); } var_dump($msg, (string) $msg->getBody()); ?> DONE --EXPECTF-- Test object(http\Message)#%d (9) { ["type":protected]=> int(1) ["body":protected]=> object(http\Message\Body)#%d (0) { } ["requestMethod":protected]=> string(3) "GET" ["requestUrl":protected]=> string(1) "/" ["responseStatus":protected]=> string(0) "" ["responseCode":protected]=> int(0) ["httpVersion":protected]=> string(3) "1.1" ["headers":protected]=> array(3) { ["Host"]=> string(9) "localhost" ["Content-Length"]=> string(1) "3" ["X-Original-Content-Length"]=> string(1) "3" } ["parentMessage":protected]=> NULL } string(3) "OK " DONE pecl_http-3.0.1/tests/negotiate001.phpt0000644000175000001440000000433412667772426016627 0ustar mikeusers--TEST-- negotiate --SKIPIF-- --ENV-- HTTP_ACCEPT=text/html,text/plain,text/xml;q=0.1,image/*;q=0.1,*/*;q=0 HTTP_ACCEPT_CHARSET=utf-8,iso-8859-1;q=0.8,iso-8859-15;q=0 HTTP_ACCEPT_ENCODING=gzip,deflate;q=0 HTTP_ACCEPT_LANGUAGE=de-DE,de-AT;q=0.9,en;q=0.8,fr;q=0 --FILE-- CONTENT TYPE CHARSET ENCODING LANGUAGE CUSTOM DONE --EXPECT-- CONTENT TYPE text/html: Array ( [text/html] => 0.99 [text/xml] => 0.1 ) text/xml: Array ( [text/xml] => 0.1 ) text/json: Array ( ) CHARSET utf-8: Array ( [utf-8] => 0.99 [iso-8859-1] => 0.8 ) iso-8859-1: Array ( [iso-8859-1] => 0.8 ) utf-16: Array ( ) ENCODING gzip: Array ( [gzip] => 0.99 ) : Array ( ) LANGUAGE de: Array ( [de] => 0.99 [en] => 0.8 ) de-DE: Array ( [de-DE] => 0.99 [de-AT] => 0.9 [en] => 0.8 ) en: Array ( [en] => 0.8 ) CUSTOM a.b: Array ( [a.b] => 0.9 [a.x] => 0.1 [c.e] => 0.1 ) DONE pecl_http-3.0.1/tests/params001.phpt0000644000175000001440000000203612667772426016130 0ustar mikeusers--TEST-- header params --SKIPIF-- --FILE-- array("charset" => "iso-8859-1")); var_dump( isset($ct["text/html"]), isset($ct["text/json"]), $ct["text/json"]["arguments"]["charset"] ); var_dump((string) $ct,$ct); ?> DONE --EXPECTF-- Test bool(true) bool(false) string(5) "utf-8" bool(false) bool(true) string(10) "iso-8859-1" string(%d) "text/json;charset=iso-8859-1" object(http\Params)#%d (5) { ["params"]=> array(1) { ["text/json"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["charset"]=> string(10) "iso-8859-1" } } } ["param_sep"]=> string(1) "," ["arg_sep"]=> string(1) ";" ["val_sep"]=> string(1) "=" ["flags"]=> int(0) } DONE pecl_http-3.0.1/tests/params002.phpt0000644000175000001440000000147712667772426016141 0ustar mikeusers--TEST-- query parser --SKIPIF-- --FILE-- DONE --EXPECTF-- object(http\Params)#%d (5) { ["params"]=> array(2) { ["foo"]=> array(2) { ["value"]=> string(3) "bar" ["arguments"]=> array(0) { } } ["arr"]=> array(2) { ["value"]=> array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } ["arguments"]=> array(0) { } } } ["param_sep"]=> array(2) { [0]=> string(1) "&" [1]=> string(1) ";" } ["arg_sep"]=> string(0) "" ["val_sep"]=> string(1) "=" ["flags"]=> int(12) } foo=bar&arr%5B0%5D=1&arr%5B1%5D=2 DONE pecl_http-3.0.1/tests/params003.phpt0000644000175000001440000000246312667772426016136 0ustar mikeusers--TEST-- default params --SKIPIF-- --FILE-- "arg", "bar"=>"bla", "gotit"=>"now"); $r = array ( 'foo' => array ( 'value' => true, 'arguments' => array ( ), ), 'bar' => array ( 'value' => true, 'arguments' => array ( 'arg' => '0', 'bla' => true, ), ), 'gotit' => array ( 'value' => '0', 'arguments' => array ( 'now' => true, ), ), ); # --- var_dump(count($p->params)); echo "key exists\n"; foreach ($k as $key) { var_dump(array_key_exists($key, $p->params)); } echo "values\n"; foreach ($k as $key) { var_dump($p[$key]["value"]); } echo "args\n"; foreach ($k as $key) { var_dump(count($p[$key]["arguments"])); } echo "arg values\n"; foreach ($k as $key) { var_dump(@$p[$key]["arguments"][$a[$key]]); } echo "equals\n"; var_dump($c === (string) $p); var_dump($r === $p->params); $x = new http\Params($p->params); var_dump($r === $x->toArray()); ?> DONE --EXPECT-- Test int(3) key exists bool(true) bool(true) bool(true) values bool(true) bool(true) string(1) "0" args int(0) int(2) int(1) arg values NULL bool(true) bool(true) equals bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/params004.phpt0000644000175000001440000000245112667772426016134 0ustar mikeusers--TEST-- custom params --SKIPIF-- --FILE-- "arg", "bar"=>"bla", "gotit"=>"now"); $r = array ( 'foo' => array ( 'value' => true, 'arguments' => array ( ), ), 'bar' => array ( 'value' => true, 'arguments' => array ( 'arg' => '0', 'bla' => true, ), ), 'gotit' => array ( 'value' => '0', 'arguments' => array ( 'now' => true, ), ), ); # --- var_dump(count($p->params)); echo "key exists\n"; foreach ($k as $key) { var_dump(array_key_exists($key, $p->params)); } echo "values\n"; foreach ($k as $key) { var_dump($p[$key]["value"]); } echo "args\n"; foreach ($k as $key) { var_dump(count($p[$key]["arguments"])); } echo "arg values\n"; foreach ($k as $key) { var_dump(@$p[$key]["arguments"][$a[$key]]); } echo "equals\n"; var_dump($c === (string) $p); var_dump($r === $p->params); $x = new http\Params($p->params); var_dump($r === $x->toArray()); ?> DONE --EXPECT-- Test int(3) key exists bool(true) bool(true) bool(true) values bool(true) bool(true) string(1) "0" args int(0) int(2) int(1) arg values NULL bool(true) bool(true) equals bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/params005.phpt0000644000175000001440000000065412667772426016140 0ustar mikeusers--TEST-- quoted params --SKIPIF-- --FILE-- array( "value" => true, "arguments" => array( "boundary" => "--123" ) ) ); var_dump($c === $p->params); var_dump("multipart/form-data;boundary=--123" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params006.phpt0000644000175000001440000000075212667772426016140 0ustar mikeusers--TEST-- escaped params --SKIPIF-- --FILE-- array( "value" => true, "arguments" => array( "name" => "upload", "filename" => "trick\"\0\"ed" ) ) ); var_dump($c === $p->params); var_dump("form-data;name=upload;filename=\"trick\\\"\\000\\\"ed\"" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params007.phpt0000644000175000001440000000110212667772426016127 0ustar mikeusers--TEST-- urlencoded params --SKIPIF-- --FILE-- array( "value" => "b\"r", "arguments" => array(), ), "bar" => array( "value" => "b\"z", "arguments" => array(), ), "a[][]" => array( "value" => "1", "arguments" => array(), ), ); var_dump($c === $p->params); var_dump("foo=b%22r&bar=b%22z&a%5B%5D%5B%5D=1" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params008.phpt0000644000175000001440000000112112667772426016131 0ustar mikeusers--TEST-- querystring params --SKIPIF-- --FILE-- array( "value" => "b\"r", "arguments" => array(), ), "bar" => array( "value" => "b\"z", "arguments" => array(), ), "a" => array( "value" => array( array("1") ), "arguments" => array(), ), ); var_dump($c === $p->params); var_dump("foo=b%22r&bar=b%22z&a%5B0%5D%5B0%5D=1" === (string) $p); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params009.phpt0000644000175000001440000000030412667772426016134 0ustar mikeusers--TEST-- empty params --SKIPIF-- --FILE-- params); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/params010.phpt0000644000175000001440000000052212667772426016126 0ustar mikeusers--TEST-- int key params --SKIPIF-- --FILE-- array("value" => "nothing", "arguments" => array(1=>"yes"))) === $p->params); var_dump("0=nothing;1=yes" === $p->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params011.phpt0000644000175000001440000000064612667772426016136 0ustar mikeusers--TEST-- bool args params --SKIPIF-- --FILE-- false, "arguments" => array("wrong" => false, "correct" => true)); $p["container"] = $container; var_dump("container=0;wrong=0;correct" === $p->toString()); var_dump(array("container" => $container) === $p->toArray()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params012.phpt0000644000175000001440000000044112667772426016130 0ustar mikeusers--TEST-- no args params --SKIPIF-- --FILE-- toString()); $p["param"] = false; var_dump("param=0" === $p->toString()); ?> DONE --EXPECT-- Test bool(true) bool(true) DONE pecl_http-3.0.1/tests/params013.phpt0000644000175000001440000000262412667772426016136 0ustar mikeusers--TEST-- header params rfc5987 --SKIPIF-- --FILE-- params, (string) $p); $p = new http\Params("bar; title*=iso-8859-1'en'%A3%20rates"); var_dump($p->params, (string) $p); $p = new http\Params("bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates"); var_dump($p->params, (string) $p); ?> ===DONE=== --EXPECT-- Test array(1) { ["attachment"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["filename"]=> array(1) { [""]=> string(10) "dΓΆner.pdf" } } } } } string(42) "attachment;filename*=utf-8''d%C3%B6ner.pdf" array(1) { ["bar"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["en"]=> string(8) "Β£ rates" } } } } } string(34) "bar;title*=utf-8'en'%C2%A3%20rates" array(1) { ["bar"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { [""]=> string(16) "Β£ and € rates" } } } } } string(50) "bar;title*=utf-8''%C2%A3%20and%20%E2%82%AC%20rates" ===DONE=== pecl_http-3.0.1/tests/params014.phpt0000644000175000001440000000236612667772426016142 0ustar mikeusers--TEST-- header params rfc5987 --SKIPIF-- --FILE-- params); var_dump((string)$p === $t, (string)$p, $t); ?> ===DONE=== --EXPECT-- Test array(3) { ["p1"]=> array(2) { ["*rfc5987*"]=> array(1) { [""]=> string(5) "süß" } ["arguments"]=> array(0) { } } ["p2"]=> array(2) { ["*rfc5987*"]=> array(1) { [""]=> string(5) "heiß" } ["arguments"]=> array(2) { ["*rfc5987*"]=> array(2) { ["a1"]=> array(1) { [""]=> string(3) "aß" } ["a2"]=> array(1) { [""]=> string(3) "eß" } } ["a3"]=> string(2) "no" } } ["p3"]=> array(2) { ["value"]=> string(3) "not" ["arguments"]=> array(0) { } } } bool(true) string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" string(96) "p1*=utf-8''s%C3%BC%C3%9F,p2*=utf-8''hei%C3%9F;a1*=utf-8''a%C3%9F;a2*=utf-8''e%C3%9F;a3=no,p3=not" ===DONE=== pecl_http-3.0.1/tests/params015.phpt0000644000175000001440000000062512667772426016137 0ustar mikeusers--TEST-- header params rfc5987 regression --SKIPIF-- --FILE-- array("filename"=>"foo.bar"))); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECT-- Test array(1) { ["attachment"]=> array(1) { ["filename"]=> string(7) "foo.bar" } } string(27) "attachment;filename=foo.bar" ===DONE=== pecl_http-3.0.1/tests/params016.phpt0000644000175000001440000000206512667772426016140 0ustar mikeusers--TEST-- header params rfc5988 --SKIPIF-- --FILE-- ; rel="next", ; rel="last" EOF; $p = new http\Params($link, ",", ";", "=", http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECT-- Test array(2) { ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=2"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["rel"]=> string(4) "next" } } ["https://api.github.com/search/code?q=addClass+user%3Amozilla&page=34"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(1) { ["rel"]=> string(4) "last" } } } string(162) ";rel="next",;rel="last"" ===DONE=== pecl_http-3.0.1/tests/params017.phpt0000644000175000001440000000255512667772426016145 0ustar mikeusers--TEST-- header params rfc5988 --SKIPIF-- --FILE-- ; rel="previous"; title*=UTF-8'de'letztes%20Kapitel, ; rel="next"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel EOF; $p = current(http\Header::parse($link, "http\\Header"))->getParams( http\Params::DEF_PARAM_SEP, http\Params::DEF_ARG_SEP, http\Params::DEF_VAL_SEP, http\Params::PARSE_RFC5988 | http\Params::PARSE_ESCAPED ); var_dump($p->params); var_dump((string)$p); ?> ===DONE=== --EXPECTF-- Test array(2) { ["/TheBook/chapter2"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(2) { ["rel"]=> string(8) "previous" ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["de"]=> string(15) "letztes Kapitel" } } } } ["/TheBook/chapter4"]=> array(2) { ["value"]=> bool(true) ["arguments"]=> array(2) { ["rel"]=> string(4) "next" ["*rfc5987*"]=> array(1) { ["title"]=> array(1) { ["de"]=> string(17) "nΓ€chstes Kapitel" } } } } } string(139) ";rel="previous";title*=utf-8'de'letztes%20Kapitel,;rel="next";title*=utf-8'de'n%C3%A4chstes%20Kapitel" ===DONE=== pecl_http-3.0.1/tests/phpinfo.phpt0000644000175000001440000000030612667772426016065 0ustar mikeusers--TEST-- phpinfo --SKIPIF-- --FILE-- Done --EXPECTF-- Test %a HTTP Support => enabled Extension Version => 3.%s %a Done pecl_http-3.0.1/tests/propertyproxy001.phpt0000644000175000001440000000236212667772426017635 0ustar mikeusers--TEST-- property proxy --SKIPIF-- --FILE-- headers["bykey"] = 1; var_dump($this->headers); $h = &$this->headers; $h["by1ref"] = 2; var_dump($this->headers); $x = &$this->headers["byXref"]; $h = &$this->headers["by2ref"]; $h = 1; var_dump($this->headers); $x = 2; var_dump($this->headers); $this->headers["bynext"][] = 1; $this->headers["bynext"][] = 2; $this->headers["bynext"][] = 3; var_dump($this->headers); } } $m=new m; $m->test(); echo $m,"\n"; ?> DONE --EXPECTF-- array(1) { ["bykey"]=> int(1) } array(2) { ["bykey"]=> int(1) ["by1ref"]=> int(2) } array(3) { ["bykey"]=> int(1) ["by1ref"]=> int(2) ["by2ref"]=> int(1) } array(4) { ["bykey"]=> int(1) ["by1ref"]=> int(2) ["by2ref"]=> int(1) ["byXref"]=> int(2) } array(5) { ["bykey"]=> int(1) ["by1ref"]=> int(2) ["by2ref"]=> int(1) ["byXref"]=> int(2) ["bynext"]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } bykey: 1 by1ref: 2 by2ref: 1 byXref: 2 bynext: 1, 2, 3 DONE pecl_http-3.0.1/tests/querystring001.phpt0000644000175000001440000000677212667772426017254 0ustar mikeusers--TEST-- query string --SKIPIF-- --GET-- str=abc&num=-123&dec=123.123&bool=1&arr[]=1&arr[]=2&ma[l1][l2]=2&ma[l2][l3][l4]=3 --FILE-- getString("str")); var_dump($q->getInt("num")); var_dump($q->getFloat("dec")); var_dump($q->getInt("dec")); var_dump($q->getFloat("dec")); var_dump($q->getBool("bool")); var_dump($q->getInt("bool")); var_dump($q->getBool("num")); var_dump($q->getInt("num")); var_dump($q->getArray("arr")); var_dump($q->getArray("ma")); var_dump($q->getObject("arr")); var_dump($q->getObject("ma")); $s = $q->toString(); printf("\nClone modifications do not alter global instance:\n"); $q->mod(array("arr" => array(3 => 3))); printf("%s\n", $q); printf("\nClone modifications do not alter standard instance:\n"); $q2 = new http\QueryString($s); $q3 = $q2->mod(array("arr" => array(3 => 3))); printf("%s\n%s\n", $q2, $q3); #var_dump($q2, $q3); printf("\nIterator:\n"); $it = new RecursiveIteratorIterator($q2, RecursiveIteratorIterator::SELF_FIRST); foreach ($it as $k => $v) { $i = $it->getDepth()*8; @printf("%{$i}s: %s\n", $k, $v); } printf("\nReplace a multi dimensional key:\n"); printf("%s\n", $q2->mod(array("ma" => null))->set(array("ma" => array("l1" => false)))); printf("\nXlate:\n"); $qu = new http\QueryString("ΓΌ=ΓΆ"); printf("utf8: %s\n", $qu); printf("latin1: %s\n", method_exists($qu, "xlate") ? $qu->xlate("utf-8", "latin1") : "%FC=%F6"); printf("\nOffsets:\n"); var_dump($q2["ma"]); $q2["ma"] = array("bye"); var_dump($q2["ma"]); var_dump(isset($q2["ma"])); unset($q2["ma"]); var_dump(isset($q2["ma"])); echo "Done\n"; ?> --EXPECTF-- Test Global instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Standard getters: string(3) "abc" int(-123) float(123.123) int(123) float(123.123) bool(true) int(1) bool(true) int(-123) array(2) { [0]=> string(1) "1" [1]=> string(1) "2" } array(2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } object(stdClass)#%d (2) { [0]=> string(1) "1" [1]=> string(1) "2" } object(stdClass)#%d (2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } Clone modifications do not alter global instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Clone modifications do not alter standard instance: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&arr%5B3%5D=3&ma%5Bl1%5D%5Bl2%5D=2&ma%5Bl2%5D%5Bl3%5D%5Bl4%5D=3 Iterator: str: abc num: -123 dec: 123.123 bool: 1 arr: Array 0: 1 1: 2 ma: Array l1: Array l2: 2 l2: Array l3: Array l4: 3 Replace a multi dimensional key: str=abc&num=-123&dec=123.123&bool=1&arr%5B0%5D=1&arr%5B1%5D=2&ma%5Bl1%5D= Xlate: utf8: %C3%BC=%C3%B6 latin1: %FC=%F6 Offsets: array(2) { ["l1"]=> array(1) { ["l2"]=> string(1) "2" } ["l2"]=> array(1) { ["l3"]=> array(1) { ["l4"]=> string(1) "3" } } } array(1) { [0]=> string(3) "bye" } bool(true) bool(false) Done pecl_http-3.0.1/tests/querystring002.phpt0000644000175000001440000000355412667772426017250 0ustar mikeusers--TEST-- query string --SKIPIF-- --FILE-- get()); printf("Get defval\n"); var_dump("nonexistant" === $q->get("unknown", "s", "nonexistant")); var_dump(null === $q->get("unknown")); printf("Get 'a'\n"); var_dump("b" === $q->get("a")); var_dump(0 === $q->get("a", "i")); var_dump(array("b") === $q->get("a", "a")); var_dump((object)array("scalar" => "b") == $q->get("a", "o")); printf("Get 'r'\n"); var_dump(array("0","1","2") === $q->get("r")); printf("Get 'rr'\n"); var_dump(array(array("00","01")) === $q->get("rr")); printf("Get 1\n"); var_dump(2 == $q->get(1)); var_dump("2" === $q->get(1, "s")); var_dump(2.0 === $q->get(1, "f")); var_dump($q->get(1, "b")); printf("Del 'a'\n"); var_dump("b" === $q->get("a", http\QueryString::TYPE_STRING, null, true)); var_dump(null === $q->get("a")); printf("Del all\n"); $q->set(array("a" => null, "r" => null, "rr" => null, 1 => null)); var_dump("" === $q->toString()); $q = new http\QueryString($s); printf("QSO\n"); var_dump($e === (string) new http\QueryString($q)); var_dump(http_build_query(array("e"=>$q->toArray())) === (string) new http\QueryString(array("e" => $q))); printf("Iterator\n"); var_dump($q->toArray() === iterator_to_array($q)); printf("Serialize\n"); var_dump($e === (string) unserialize(serialize($q))); ?> DONE --EXPECT-- Test bool(true) bool(true) Get defval bool(true) bool(true) Get 'a' bool(true) bool(true) bool(true) bool(true) Get 'r' bool(true) Get 'rr' bool(true) Get 1 bool(true) bool(true) bool(true) bool(true) Del 'a' bool(true) bool(true) Del all bool(true) QSO bool(true) bool(true) Iterator bool(true) Serialize bool(true) DONE pecl_http-3.0.1/tests/querystring003.phpt0000644000175000001440000000042412667772426017242 0ustar mikeusers--TEST-- querystring offset set --SKIPIF-- --FILE-- ===DONE=== --EXPECT-- Test foo=bar&bar=baz bar=baz&foo=baz ===DONE=== pecl_http-3.0.1/tests/serialize001.phpt0000644000175000001440000000104312667772426016631 0ustar mikeusers--TEST-- serialization --SKIPIF-- --FILE-- getClasses() as $class) { if ($class->isInstantiable()) { #printf("%s\n", $class->getName()); $instance = $class->newInstance(); $serialized = serialize($instance); $unserialized = unserialize($serialized); foreach (array("toString", "toArray") as $m) { if ($class->hasMethod($m)) { #printf("%s#%s\n", $class->getName(), $m); $unserialized->$m(); } } } } ?> DONE --EXPECTF-- DONE pecl_http-3.0.1/tests/url001.phpt0000644000175000001440000000157612667772426015457 0ustar mikeusers--TEST-- url from env --SKIPIF-- --ENV-- SERVER_PORT=55555 HTTP_HOST=example.com --GET-- s=b&i=0&e=&a[]=1&a[]=2 --FILE-- "https", "port" => 443))); printf("%s\n", new http\Env\Url(array("path" => "/./up/../down/../././//index.php/.", "query" => null), null, http\Url::SANITIZE_PATH|http\Url::FROM_ENV)); printf("%s\n", new http\Env\Url(null, null, 0)); printf("%s\n", new http\Url(null, null, http\Url::FROM_ENV)); ?> DONE --EXPECTF-- http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/index?s=b&i=0&e=&a[]=1&a[]=2 https://example.com/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/index.php/ http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 http://example.com:55555/?s=b&i=0&e=&a[]=1&a[]=2 DONE pecl_http-3.0.1/tests/url002.phpt0000644000175000001440000000144012667772426015446 0ustar mikeusers--TEST-- url properties --SKIPIF-- --FILE-- "changed", "query" => "foo=&added=this"), http\Url::JOIN_PATH | http\Url::JOIN_QUERY | http\Url::STRIP_AUTH | http\Url::STRIP_FRAGMENT ); var_dump($url->scheme); var_dump($url->user); var_dump($url->pass); var_dump($url->host); var_dump($url->port); var_dump($url->path); var_dump($url->query); var_dump($url->fragment); ?> DONE --EXPECT-- Test bool(true) string(4) "http" NULL NULL string(15) "www.example.com" int(8080) string(13) "/path/changed" string(38) "more%5B0%5D=1&more%5B1%5D=2&added=this" NULL DONE pecl_http-3.0.1/tests/url003.phpt0000644000175000001440000000076212667772426015455 0ustar mikeusers--TEST-- url modification --SKIPIF-- --FILE-- mod(array("query" => "set=1"), http\Url::REPLACE); var_dump($tmp->toArray() != $mod->toArray()); var_dump("set=1" === $mod->query); var_dump("new_fragment" === $tmp->mod("#new_fragment")->fragment); ?> DONE --EXPECT-- Test bool(true) bool(true) bool(true) DONE pecl_http-3.0.1/tests/url004.phpt0000644000175000001440000000050612667772426015452 0ustar mikeusers--TEST-- url as string --SKIPIF-- --FILE-- DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/url005.phpt0000644000175000001440000000053212667772426015452 0ustar mikeusers--TEST-- url as array --SKIPIF-- --FILE-- toArray()); var_dump($url->toArray() === $url2->toArray()); ?> DONE --EXPECT-- Test bool(true) DONE pecl_http-3.0.1/tests/urlparser001.phpt0000644000175000001440000000376212667772426016673 0ustar mikeusers--TEST-- url parser --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s: object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss: object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s:a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "a" ["query"]=> NULL ["fragment"]=> NULL } ss:aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(2) "aa" ["query"]=> NULL ["fragment"]=> NULL } s:// object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss:// object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "a" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } ss://aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "aa" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser002.phpt0000644000175000001440000000454512667772426016674 0ustar mikeusers--TEST-- url parser with paths --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s:a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(2) "a/" ["query"]=> NULL ["fragment"]=> NULL } ss:aa/ object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(3) "aa/" ["query"]=> NULL ["fragment"]=> NULL } s:/a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(3) "/a/" ["query"]=> NULL ["fragment"]=> NULL } ss:/aa/ object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(4) "/aa/" ["query"]=> NULL ["fragment"]=> NULL } s://a/ object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "a" ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> NULL ["fragment"]=> NULL } s://h/a object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> string(2) "/a" ["query"]=> NULL ["fragment"]=> NULL } ss://hh/aa object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> string(3) "/aa" ["query"]=> NULL ["fragment"]=> NULL } s:///a/b object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(4) "/a/b" ["query"]=> NULL ["fragment"]=> NULL } ss:///aa/bb object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(6) "/aa/bb" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser003.phpt0000644000175000001440000000624712667772426016676 0ustar mikeusers--TEST-- url parser with query --SKIPIF-- --FILE-- DONE --EXPECTF-- Test s:?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss:?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s:/?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss:/?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> string(1) "/" ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> NULL ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h/p?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> string(2) "/p" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh/pp?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> NULL ["path"]=> string(3) "/pp" ["query"]=> string(2) "qq" ["fragment"]=> NULL } s://h:123/p/?q object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> int(123) ["path"]=> string(3) "/p/" ["query"]=> string(1) "q" ["fragment"]=> NULL } ss://hh:123/pp/?qq object(http\Url)#%d (8) { ["scheme"]=> string(2) "ss" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(2) "hh" ["port"]=> int(123) ["path"]=> string(4) "/pp/" ["query"]=> string(2) "qq" ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser004.phpt0000644000175000001440000000240212667772426016664 0ustar mikeusers--TEST-- url parser multibyte/locale --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sΓ§heme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hƟst" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst:23/pΓ€th/ΓΆf/fΔ±le object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hƟst" ["port"]=> int(23) ["path"]=> string(16) "/pΓ€th/ΓΆf/fΔ±le" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser005.phpt0000644000175000001440000000214012667772426016664 0ustar mikeusers--TEST-- url parser multibyte/utf-8 --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sΓ§heme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hƟst" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst:23/pΓ€th/ΓΆf/fΔ±le object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "hƟst" ["port"]=> int(23) ["path"]=> string(16) "/pΓ€th/ΓΆf/fΔ±le" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser006.phpt0000644000175000001440000000255212667772426016674 0ustar mikeusers--TEST-- url parser multibyte/locale/idna --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sΓ§heme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst:23/pΓ€th/ΓΆf/fΔ±le object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> int(23) ["path"]=> string(16) "/pΓ€th/ΓΆf/fΔ±le" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser007.phpt0000644000175000001440000000234712667772426016677 0ustar mikeusers--TEST-- url parser multibyte/utf-8/idna --SKIPIF-- --FILE-- DONE --EXPECTF-- Test sΓ§heme: object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } sΓ§heme://hƟst:23/pΓ€th/ΓΆf/fΔ±le object(http\Url)#%d (8) { ["scheme"]=> string(7) "sΓ§heme" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(11) "xn--hst-kwb" ["port"]=> int(23) ["path"]=> string(16) "/pΓ€th/ΓΆf/fΔ±le" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser008.phpt0000644000175000001440000000210512667772426016670 0ustar mikeusers--TEST-- url parser ipv6 --SKIPIF-- --FILE-- getMessage(),"\n"; } } ?> DONE --EXPECTF-- Test s://[a:80 http\Url::__construct(): Failed to parse hostinfo; expected ']' s://[0] http\Url::__construct(): Failed to parse hostinfo; unexpected '[' s://[::1]:80 object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> NULL ["pass"]=> NULL ["host"]=> string(5) "[::1]" ["port"]=> int(80) ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://mike@[0:0:0:0:0:FFFF:204.152.189.116]/foo object(http\Url)#%d (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "mike" ["pass"]=> NULL ["host"]=> string(24) "[::ffff:204.152.189.116]" ["port"]=> NULL ["path"]=> string(4) "/foo" ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser009.phpt0000644000175000001440000000645512667772426016705 0ustar mikeusers--TEST-- url parser userinfo --SKIPIF-- --FILE-- getMessage(),"\n"; } } ?> DONE --EXPECTF-- Test s://:@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(0) "" ["pass"]=> string(0) "" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u:@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> string(0) "" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u:p@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> string(1) "p" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@ object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> NULL ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> NULL ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://u@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(1) "u" ["pass"]=> NULL ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:p@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(1) "p" ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@h object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(1) "h" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } s://user:pass@host object(http\Url)#1 (8) { ["scheme"]=> string(1) "s" ["user"]=> string(4) "user" ["pass"]=> string(4) "pass" ["host"]=> string(4) "host" ["port"]=> NULL ["path"]=> NULL ["query"]=> NULL ["fragment"]=> NULL } DONE pecl_http-3.0.1/tests/urlparser010.phpt0000644000175000001440000000146012667772426016664 0ustar mikeusers--TEST-- url parser multibyte/locale/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(15) "πŒ€πŒπŒ‚.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-3.0.1/tests/urlparser011.phpt0000644000175000001440000000121412667772426016662 0ustar mikeusers--TEST-- url parser multibyte/utf-8/topct --SKIPIF-- --FILE-- DONE --EXPECTF-- Test object(http\Url)#%d (8) { ["scheme"]=> string(4) "http" ["user"]=> string(4) "mike" ["pass"]=> string(12) "pa%C3%9Fwort" ["host"]=> string(15) "πŒ€πŒπŒ‚.it" ["port"]=> NULL ["path"]=> string(15) "/for/%E2%82%AC/" ["query"]=> string(9) "by=%C2%A2" ["fragment"]=> string(6) "%C3%B8" } DONE pecl_http-3.0.1/tests/version001.phpt0000644000175000001440000000072412667772426016334 0ustar mikeusers--TEST-- version parse error --SKIPIF-- --FILE-- setHttpVersion("1-1"); $m->setHttpVersion("one.one"); } catch (http\Exception $e) { echo $e->getMessage(),"\n"; } ?> --EXPECTF-- Notice: http\Message::setHttpVersion(): Non-standard version separator '-' in HTTP protocol version '1-1' in %s http\Message::setHttpVersion(): Could not parse HTTP protocol version 'one.one' pecl_http-3.0.1/scripts/bench_select_vs_event.php0000644000175000001440000000253112667772426021114 0ustar mikeusers -n -c [-p (enable pipelining)] [-e (use libevent)]\n", $argv[0]); fprintf(STDERR, "\nDefaults: -u http://localhost/ -n 1000 -c 10\n\n"); exit(-1); } function push($client, $url, &$n) { if ($n-- > 0) { $req = new http\Client\Request("GET", $url); $client->enqueue($req, function($response) use ($client, $req, $url, &$n) { global $count; ++$count; push($client, $url, $n); return true; // dequeue }); } } isset($argv) or $argv = $_SERVER['argv']; defined('STDERR') or define('STDERR', fopen('php://stderr', 'w')); $opts = getopt("u:c:n:e"); isset($opts["u"]) or $opts["u"] = "http://localhost/"; isset($opts["c"]) or $opts["c"] = 10; isset($opts["n"]) or $opts["n"] = 1000; $argc > 1 or usage(); $time = microtime(true); $count = 0; $client = new http\Client; $client->enablePipelining($opts["p"]===false); $client->enableEvents($opts["e"]===false); for ($i = 0, $x = $opts["n"]; $i < $opts["c"]; ++$i) { push($client, $opts["u"], $x); } try { $client->send(); } catch (Exception $e) { echo $e; } printf("\n> %10.6fs (%3.2fM)\n", microtime(true)-$time, memory_get_peak_usage(true)/1024/1024); $count == $opts["n"] or printf("\nOnly %d finished\n", $count); pecl_http-3.0.1/scripts/check_package-xml.php0000755000175000001440000000513712667772426020123 0ustar mikeusers#!/usr/bin/env php 1) { if ($argv[1] === "-") { $file = "php://stdin"; } else { $file = $argv[1]; } } elseif (stdin_is_readable()) { $file = "php://stdin"; } else { $file = "./package.xml"; } if (($xml = simplexml_load_file($file))) { $xml_files = xmllist($xml->contents[0]); $dirs = ["."]; while ($dir = array_shift($dirs)) { foreach (dirlist($dir) as $file) { if (is_gitignored($file)) { continue; } if (is_commonly_ignored($file)) { continue; } if (!is_dir($file)) { if (!in_array($file, $xml_files)) { echo "Missing file $file\n"; } } else { $base = basename($file); if ($base{0} !== ".") { array_push($dirs, $file); } } } } foreach ($xml_files as $file) { if (!file_exists($file)) { echo "Extraneous file $file\n"; } } } ### function error($fmt) { trigger_error(call_user_func_array("sprintf", func_get_args())); } function stdin_is_readable() { $r = [STDIN]; $w = $e = []; return stream_select($r, $w, $e, 0); } function is_gitignored($file) { static $gitignore, $gitmodules; if (!isset($gitmodules)) { if (is_readable("./.gitmodules")) { $gitmodules = explode("\n", `git submodule status | awk '{printf$2}'`); } else { $gitmodules = false; } } if (!isset($gitignore)) { if (is_readable("./.gitignore")) { $ignore_submodules = $gitmodules ? " ! -path './".implode("/*' ! -path './", $gitmodules)."/*'" : ""; $gitignore = explode("\n", `find . $ignore_submodules | git check-ignore --stdin`); } else { $gitignore = false; } } if ($gitignore) { if (in_array($file, $gitignore)) { return true; } } if ($gitmodules) { foreach ($gitmodules as $module) { if (fnmatch("./$module/*", $file)) { return true; } } } return false; } function is_commonly_ignored($file) { return fnmatch("./.git*", $file) || in_array($file, ["./package.xml", "./package2.xml", "./.travis.yml", "./.editorconfig"], true); } function xmllist(SimpleXmlElement $dir, $p = ".", &$a = null) { settype($a, "array"); $p = trim($p, "/") . "/" . trim($dir["name"], "/") . "/"; foreach ($dir as $file) { switch ($file->getName()) { case "dir": xmllist($file, $p, $a); break; case "file": $a[] = sprintf("%s/%s", trim($p, "/"), trim($file["name"])); break; default: error("Unknown content type: %s", $file->getName()); break; } } return $a; } function dirlist($dir, $p = null) { $p = implode("/", array_filter([trim($p, "/"), trim($dir, "/")])); foreach (scandir($p) as $file) { yield $p."/".$file; } } pecl_http-3.0.1/scripts/gen_curlinfo.php0000755000175000001440000000534412667772426017247 0ustar mikeusers#!/usr/bin/env php 'PHP_HTTP_CURL_VERSION(7,19,0)', 'APPCONNECT_TIME' => 'PHP_HTTP_CURL_VERSION(7,19,0)', 'CONDITION_UNMET' => 'PHP_HTTP_CURL_VERSION(7,19,4)', 'PRIMARY_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', 'LOCAL_PORT' => 'PHP_HTTP_CURL_VERSION(7,21,0)', 'LOCAL_IP' => 'PHP_HTTP_CURL_VERSION(7,21,0)', ); $exclude = array( 'PRIVATE', 'LASTSOCKET', 'FTP_ENTRY_PATH', 'CERTINFO', 'TLS_SESSION', 'RTSP_SESSION_ID', 'RTSP_CLIENT_CSEQ', 'RTSP_SERVER_CSEQ', 'RTSP_CSEQ_RECV', 'COOKIELIST' ); $translate = array( 'HTTP_CONNECTCODE' => "connect_code", 'COOKIELIST' => 'cookies', ); $templates = array( 'STRING' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &c)) { ZVAL_STRING(&tmp, STR_PTR(c)); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'DOUBLE' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &d)) { ZVAL_DOUBLE(&tmp, d); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'LONG' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &l)) { ZVAL_LONG(&tmp, l); zend_hash_str_update(info, "%s", lenof("%2$s"), &tmp); } ', 'SLIST' => ' if (CURLE_OK == curl_easy_getinfo(ch, %s, &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, "%s", lenof("%2$s"), &tmp); curl_slist_free_all(s); } ', ); $infos = file_re('curl.h', '/^\s*(CURLINFO_(\w+))\s*=\s*CURLINFO_(STRING|LONG|DOUBLE|SLIST)\s*\+\s*\d+\s*,?\s*$/m'); ob_start(); foreach ($infos as $info) { list(, $full, $short, $type) = $info; if (in_array($short, $exclude)) continue; if (isset($ifdefs[$short])) printf("#if %s\n", $ifdefs[$short]); printf($templates[$type], $full, strtolower((isset($translate[$short])) ? $translate[$short] : $short)); if (isset($ifdefs[$short])) printf("#endif\n"); } file_put_contents("php_http_client_curl.c", preg_replace('/(\/\* BEGIN::CURLINFO \*\/\n).*(\n\s*\/\* END::CURLINFO \*\/)/s', '$1'. ob_get_contents() .'$2', file_get_contents("php_http_client_curl.c"))); ?> pecl_http-3.0.1/scripts/gen_stubs.php0000755000175000001440000001525712667772426016572 0ustar mikeusers#!/usr/bin/env php getClass()) return "\\" . $c->getName() . " "; if ($p->isArray()) return "array "; } function c($n, $c) { $_=$c; while ($c = $c->getParentClass()) { if (array_key_exists($n, $c->getConstants())) { return false; } } $c=$_; foreach ((array) $c->getInterfaces() as $i) { if (array_key_exists($n, $i->getConstants()) || !c($n, $i)) { return false; } } return true; } ob_start(function($s) { // redirect any output to stderr fwrite(STDERR, $s); return true; }); $out = STDOUT; switch ($argc) { default: case 3: $out = fopen($argv[2], "w") or die; case 2: $ext = $argv[1]; break; case 1: die(sprintf($out, "Usage: %s \n", $argv[0])); } fprintf($out, "getConstants() as $constant => $value) { $ns = ($nsend = strrpos($constant, "\\")) ? substr($constant, 0, $nsend++) : ""; $cn = substr($constant, $nsend); $constants[$ns][$cn] = $value; } foreach ($ext->getFunctions() as $f) { /* @var $f ReflectionFunction */ $ns = $f->inNamespace() ? $f->getNamespaceName() : ""; $functions[$ns][$f->getShortName()] = $f; } foreach ($ext->getClasses() as $c) { /* @var $c ReflectionClass */ $ns = $c->inNamespace() ? $c->getNamespaceName() : ""; $structures[$ns][$c->getShortName()] = $c; } $namespaces = array_unique(array_merge( array_keys($constants), array_keys($functions), array_keys($structures) )); // simple sort natsort($namespaces); foreach ($namespaces as $ns) { fprintf($out, "namespace %s%s\n{\n", $ns, strlen($ns) ? " " : ""); // if (isset($constants[$ns])) { ksort($constants[$ns], SORT_NATURAL); foreach ($constants[$ns] as $cn => $value) { fprintf($out, "\tconst %s = %s;\n", $cn, var_export($value, true)); } } // if (isset($functions[$ns])) { ksort($functions[$ns], SORT_NATURAL); foreach ($functions[$ns] as $fn => $f) { /* @var $f ReflectionFunction */ fprintf($out, "\n\tfunction %s(", $fn); $ps = array(); foreach ($f->getParameters() as $p) { $p1 = sprintf("%s%s\$%s", t($p), $p->isPassedByReference()?"&":"", trim($p->getName(), "\"")); if ($p->isOptional()) { if ($p->isDefaultValueAvailable()) { $p1 .= sprintf(" = %s", var_export($p->getDefaultValue(), true)); } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { $p1 .= " = NULL"; } elseif ($p->isArray()) { $p1 .= " = array()"; } } $ps[] = $p1; } fprintf($out, "%s) {\n\t}\n", implode(", ", $ps)); } } // if (isset($structures[$ns])) { uasort($structures[$ns], function ($a, $b) { /* @var $a ReflectionClass */ /* @var $b ReflectionClass */ $score = array_sum([ -!$a->isInterface()+ -!$a->isAbstract()+ -!$a->isTrait()+ -!substr_compare($a->getShortName(), "Exception", -strlen("Exception")), +!$b->isInterface()+ +!$b->isAbstract()+ +!$b->isTrait()+ -!substr_compare($b->getShortName(), "Exception", -strlen("Exception")), ]); if ($score) { return -$score; } return strnatcmp($a->getShortName(), $b->getShortName()); }); foreach ($structures[$ns] as $cn => $c) { fprintf($out, "\n\t%s%s %s ", m($c->getModifiers()), $c->isInterface() ? "interface":"class", $c->getShortName()); if ($p = $c->getParentClass()) { fprintf($out, "extends \\%s ", $p->getName()); } if ($i = $c->getInterfaceNames()) { fprintf($out, "implements \\%s ", implode(", \\", array_filter($i, function($v) { return $v != "Traversable"; })) ); } fprintf($out, "\n\t{\n"); $_=0; foreach ($c->getConstants() as $n => $v) { c($n, $c) and $_+=fprintf($out, "\t\tconst %s = %s;\n", $n, var_export($v, true)); } $_ and fprintf($out, "\n"); $_=0; foreach ($c->getProperties() as $p) { if ($p->getDeclaringClass()->getName() == $c->getName()) { $_+=fprintf($out, "\t\t%s\$%s;\n", m($p->getModifiers()), $p->getName()); } } $_ and fprintf($out, "\n"); foreach ($c->getMethods() as $m) { if ($m->getDeclaringClass()->getName() == $c->getName()) { fprintf($out, "\t\t%sfunction %s(", m($m->getModifiers()), $m->getName()); $ps = array(); foreach ($m->getParameters() as $p) { $p1 = sprintf("%s%s\$%s", t($p), $p->isPassedByReference()?"&":"", $p->getName()); if ($p->isOptional()) { if ($p->isDefaultValueAvailable()) { $p1 .= sprintf(" = %s", var_export($p->getDefaultValue(), true)); } elseif (!($p->isArray() || $p->getClass()) || $p->allowsNull()) { $p1 .= sprintf(" = NULL"); } elseif ($p->isArray()) { $p1 .= " = array()"; } } $ps[] = $p1; } fprintf($out, "%s)", implode(", ", $ps)); if ($m->isAbstract()) { fprintf($out, ";\n\n"); } else { fprintf($out, " {\n\t\t}\n\n"); } } } fprintf($out, "\t}\n"); } } // fprintf($out, "}\n\n"); } pecl_http-3.0.1/scripts/gen_travis_yml.php0000755000175000001440000000201312667772426017605 0ustar mikeusers#!/usr/bin/env php # autogenerated file; do not edit language: c addons: apt: packages: - php5-cli - php-pear - libcurl4-openssl-dev - zlib1g-dev - libidn11-dev - libevent-dev env: ["7.0", "master"], "enable_debug", "enable_maintainer_zts", "enable_json", "enable_hash" => ["yes"], "enable_iconv" => ["yes"], "enable_phar" => ["yes"], "enable_posix" => ["yes"] ]); foreach ($env as $e) { printf(" - %s\n", $e); } ?> before_script: - make -f travis/pecl/Makefile php - make -f travis/pecl/Makefile pecl PECL=raphf:raphf:2.0.0 - make -f travis/pecl/Makefile pecl PECL=propro:propro:2.0.0 - make -f travis/pecl/Makefile ext PECL=http script: - make -f travis/pecl/Makefile test after_script: - test -e tests/helper/server.log && cat tests/helper/server.log sudo: false notifications: webhooks: urls: - https://webhooks.gitter.im/e/28d35158ac7e385bd14d on_success: change on_failure: always on_start: never pecl_http-3.0.1/scripts/gen_utf8.php0000755000175000001440000000342312667772426016310 0ustar mikeusers#!/usr/bin/env php = 2 ? $argv[1] : "/usr/share/i18n/locales/i18n"; $f = fopen($i18n, "r"); $c = false; $a = false; ob_start(null, 0xffff); while (!feof($f)) { $line = fgets($f); if (!$c && $line !== "LC_CTYPE\n") { continue; } $c = true; if ($line === "END LC_CTYPE\n") { break; } switch($line{0}) { case "%": break; case "\n": if ($a) { break 2; } break; case " ": if ($a) { foreach (explode(";", trim($line, "\n/ ;")) as $ranges) { $range = explode("..", $ranges); $step = 0; $end = 0; switch (count($range)) { case 3: list($sstart, $sstep, $send) = $range; sscanf($sstart, "", $start); sscanf($sstep, "(%d)", $step); sscanf($send, "", $end); break; case 2: list($sstart, $send) = $range; $step = 1; sscanf($sstart, "", $start); sscanf($send, "", $end); break; case 1: list($sstart) = $range; sscanf($sstart, "", $start); break; } print "\t{"; if ($start >= 0xffff) { printf("0x%08X, ", $start); if ($end) { printf("0x%08X, ", $end); } else { print(" 0, "); } } else { printf(" 0x%04X, ", $start); if ($end) { printf(" 0x%04X, ", $end); } else { print(" 0, "); } } printf("%d},\n", $step); } } break; default: if ($a) { break 2; } elseif ($line === "alpha /\n") { $a = true; } break; } } file_put_contents("php_http_utf8.h", preg_replace('/(\/\* BEGIN::UTF8TABLE \*\/\n).*(\n\s*\/\* END::UTF8TABLE \*\/)/s', '$1'. ob_get_contents() .'$2', file_get_contents("php_http_utf8.h"))); pecl_http-3.0.1/AUTHORS0000644000175000001440000000003712667772426013434 0ustar mikeusersMichael Wallner pecl_http-3.0.1/BUGS0000644000175000001440000000223112667772426013045 0ustar mikeusersKnown Issues ============ Windows: If you keep getting "SSL connect error" when trying to issue requests, try another (newer) libeay32.dll/ssleay32.dll pair. Internals: Inflating raw deflated data causes a re-initialization of the inflate stream where the corresponding window bits are modified to tell libz to not check for zlib header bytes. This is not preventable AFAICS. LFS dependant parts of libcurl are left out because of off_t, respectively off64_t confusion. Persistent handles and "cookiestore" request option do interfere, as libcurl saves the cookies to the file on curl_easy_destroy(), cookies are not saved until the CURL handle will be recycled. Thus one would either need to * run PHP with raphf.persistent_handles.limit = 0 * call raphf\persistent_handles_clean() every request * call $client->flushCookies(), which is available since libcurl v7.17.1 and does not work with the procedural API HTTP and Proxy authentication information (username/password) can not be unset with NULL prior libcurl v7.19.6 and separate options for setting username and password--which work--are only available since v7.19.6. pecl_http-3.0.1/CONTRIBUTING.md0000644000175000001440000000361612667772426014623 0ustar mikeusers# Contributor Code of Conduct As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery * Personal attacks * Trolling or insulting/derogatory comments * Public or private harassment * Publishing other's private information, such as physical or electronic addresses, without explicit permission * Other unethical or unprofessional conduct. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. This code of conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, available at http://contributor-covenant.org/version/1/2/0/. pecl_http-3.0.1/CREDITS0000644000175000001440000000004712667772426013405 0ustar mikeusersHTTP extension for PHP Michael Wallner pecl_http-3.0.1/LICENSE0000644000175000001440000000250712667772426013375 0ustar mikeusersCopyright (c) 2004-2015, 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. pecl_http-3.0.1/README.md0000644000175000001440000000246212667772426013647 0ustar mikeusers# ext-http [![Build Status](https://travis-ci.org/m6w6/ext-http.svg?branch=master)](https://travis-ci.org/m6w6/ext-http) [![Join the chat at https://gitter.im/m6w6/ext-http](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/m6w6/ext-http) Extended HTTP support. Again. ## Documentation See the [online markdown reference](https://mdref.m6w6.name/http). Known issues are listed in [BUGS](./BUGS) and future ideas can be found in [TODO](./TODO). ## Installing ### PECL pecl install pecl_http ### PHARext Watch out for [PECL replicates](https://replicator.pharext.org?pecl_http) and pharext packages attached to [releases](./releases). ### Checkout git clone github.com:m6w6/ext-http cd ext-http /path/to/phpize ./configure --with-php-config=/path/to/php-config make sudo make install ## ChangeLog A comprehensive list of changes can be obtained from the [PECL website](https://pecl.php.net/package-changelog.php?package=pecl_http). ## License ext-http is licensed under the 2-Clause-BSD license, which can be found in the accompanying [LICENSE](./LICENSE) file. ## Contributing All forms of contribution are welcome! Please see the bundled [CONTRIBUTING](./CONTRIBUTING.md) note for the general principles followed. The list of past and current contributors is maintained in [THANKS](./THANKS). pecl_http-3.0.1/THANKS0000644000175000001440000000117612667772426013304 0ustar mikeusersThanks go to the following people, who have contributed to this project: Ilia Alshanetsky (ilia at php dot net) Anatol Belski (ab at php dot net) Petr Czaderna (petr at hroch dot info) Remi Collet (remi at php dot net) Benjamin Eberlei (kontakt at beberlei dot de) David James (james82 at gmail dot com) Thomas Landro Johnsen (thomas dot l dot johnsen at gmail dot com) Clay Loveless (clay at killersoft dot com) Felipe Pena (felipe at php dot net) David Sklar (sklar at sklar dot com) Travis Swicegood (travis at mashery dot com) Alexey Zakhlestin (indeyets at gmail dot com) Alexander Zhuravlev (zaa at zaa dot pp dot ru) pecl_http-3.0.1/TODO0000644000175000001440000000034112667772426013052 0ustar mikeusers* let the message body be a simple query string unless files are added * php_http_message_serialize reverses the chain twice; remove that * CURLOPT_PROXY_HEADER and CURLOPT_HEADEROPT * CURLMOPT_PIPELINING changed to a bitmaskpecl_http-3.0.1/config.m40000644000175000001440000000022012667772426014065 0ustar mikeusersdnl phpize stub of config9.m4 for pecl/http dnl $Id: config.m4 214417 2006-06-07 21:05:34Z mike $ dnl vim: noet ts=1 sw=1 sinclude(config9.m4) pecl_http-3.0.1/config9.m40000644000175000001440000004111512667772426014166 0ustar mikeusersdnl config.m4 for pecl/http dnl $Id: config9.m4 242664 2007-09-18 19:13:37Z mike $ dnl vim: noet ts=4 sw=4 PHP_ARG_WITH([http], [whether to enable extended HTTP support], [ --with-http Enable extended HTTP support]) PHP_ARG_WITH([http-zlib-dir], [], [ --with-http-zlib-dir[=DIR] HTTP: where to find zlib], $PHP_HTTP, $PHP_HTTP) PHP_ARG_WITH([http-libcurl-dir], [], [ --with-http-libcurl-dir[=DIR] HTTP: where to find libcurl], $PHP_HTTP, $PHP_HTTP) PHP_ARG_WITH([http-libevent-dir], [], [ --with-http-libevent-dir[=DIR] HTTP: where to find libevent], $PHP_HTTP_LIBCURL_DIR, "") PHP_ARG_WITH([http-libidn-dir], [], [ --with-http-libidn-dir[=DIR] HTTP: where to find libidn], $PHP_HTTP_LIBCURL_DIR, "") if test "$PHP_HTTP" != "no"; then HTTP_HAVE_A_REQUEST_LIB=false ifdef([AC_PROG_EGREP], [ AC_PROG_EGREP ], [ AC_CHECK_PROG(EGREP, egrep, egrep) ]) ifdef([AC_PROG_SED], [ AC_PROG_SED ], [ ifdef([LT_AC_PROG_SED], [ LT_AC_PROG_SED ], [ AC_CHECK_PROG(SED, sed, sed) ]) ]) AC_PROG_CPP if test "$PHP_HTTP_SHARED_DEPS" != "no"; then AC_DEFINE([PHP_HTTP_SHARED_DEPS], [1], [ ]) else AC_DEFINE([PHP_HTTP_SHARED_DEPS], [0], [ ]) fi dnl dnl HTTP_SHARED_DEP(name[, code-if-yes[, code-if-not]]) dnl AC_DEFUN([HTTP_SHARED_DEP], [ extname=$1 haveext=$[PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__) AC_MSG_CHECKING([whether to add a dependency on ext/$extname]) if test "$PHP_HTTP_SHARED_DEPS" = "no"; then AC_MSG_RESULT([no]) $3 elif test "$haveext"; then AC_MSG_RESULT([yes]) AC_DEFINE([PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__), [1], [ ]) ifdef([PHP_ADD_EXTENSION_DEP], [ PHP_ADD_EXTENSION_DEP([http], $1, true) ]) $2 else AC_MSG_RESULT([no]) $3 fi ]) dnl dnl HTTP_HAVE_PHP_EXT(name[, code-if-yes[, code-if-not]]) dnl AC_DEFUN([HTTP_HAVE_PHP_EXT], [ extname=$1 haveext=$[PHP_]translit($1,a-z_-,A-Z__) AC_MSG_CHECKING([for ext/$extname support]) if test -x "$PHP_EXECUTABLE"; then grepext=`$PHP_EXECUTABLE -m | $EGREP ^$extname\$` if test "$grepext" = "$extname"; then [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 AC_MSG_RESULT([yes]) $2 else [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)= AC_MSG_RESULT([no]) $3 fi elif test "$haveext" != "no" && test "x$haveext" != "x"; then [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)=1 AC_MSG_RESULT([yes]) $2 else [PHP_HTTP_HAVE_EXT_]translit($1,a-z_-,A-Z__)= AC_MSG_RESULT([no]) $3 fi ]) dnl dnl HTTP_CURL_SSL_LIB_CHECK(ssllib[, code-if-yes[, code-if-not]) dnl AC_DEFUN([HTTP_CURL_SSL_LIB_CHECK], [ AC_MSG_CHECKING([for $1 support in libcurl]) AC_TRY_RUN([ #include int main(int argc, char *argv[]) { curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); if (data && data->ssl_version && *data->ssl_version) { const char *ptr = data->ssl_version; while(*ptr == ' ') ++ptr; return strncasecmp(ptr, "$1", sizeof("$1")-1); } return 1; } ], [ AC_MSG_RESULT([yes]) $2 ], [ AC_MSG_RESULT([no]) $3 ], [ AC_MSG_RESULT([no]) $3 ]) ]) dnl ---- dnl STDC dnl ---- AC_TYPE_OFF_T AC_TYPE_MBSTATE_T dnl getdomainname() is declared in netdb.h on some platforms: AIX, OSF AC_CHECK_HEADERS([netdb.h unistd.h wchar.h wctype.h arpa/inet.h]) PHP_CHECK_FUNC(gethostname, nsl) PHP_CHECK_FUNC(getdomainname, nsl) PHP_CHECK_FUNC(mbrtowc) PHP_CHECK_FUNC(mbtowc) PHP_CHECK_FUNC(iswalnum) PHP_CHECK_FUNC(inet_pton) dnl ---- dnl IDN dnl ---- AC_MSG_CHECKING([for idna.h]) IDNA_DIR= for i in "$PHP_HTTP_LIBIDN_DIR" "$IDN_DIR" /usr/local /usr /opt; do if test -f "$i/include/idna.h"; then IDNA_DIR=$i break; fi done if test "x$IDNA_DIR" != "x"; then AC_MSG_RESULT([found in $IDNA_DIR]) AC_DEFINE([PHP_HTTP_HAVE_IDN], [1], [Have libidn support]) PHP_ADD_INCLUDE($IDNA_DIR/include) PHP_ADD_LIBRARY_WITH_PATH(idn, $IDNA_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD) AC_MSG_CHECKING([for libidn version]) IDNA_VER=$(pkg-config --version libidn 2>/dev/null || echo unknown) AC_MSG_RESULT([$IDNA_VER]) AC_DEFINE_UNQUOTED([PHP_HTTP_LIBIDN_VERSION], "$IDNA_VER", [ ]) else AC_MSG_RESULT([not found]) AC_MSG_CHECKING([for idn2.h]) IDNA_DIR= for i in "$PHP_HTTP_LIBIDN_DIR" "$IDN_DIR" /usr/local /usr /opt; do if test -f "$i/include/idn2.h"; then IDNA_DIR=$i break; fi done if test "x$IDNA_DIR" != "x"; then AC_MSG_RESULT([found in $IDNA_DIR]) AC_DEFINE([PHP_HTTP_HAVE_IDN2], [1], [Have libidn2 support]) PHP_ADD_INCLUDE($IDNA_DIR/include) PHP_ADD_LIBRARY_WITH_PATH(idn2, $IDNA_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD) AC_MSG_CHECKING([for libidn2 version]) IDNA_VER=`$EGREP "define IDN2_VERSION " $IDNA_DIR/include/idn2.h | $SED -e's/^.*VERSION //g' -e 's/[[^0-9\.]]//g'` AC_MSG_RESULT([$IDNA_VER]) AC_DEFINE_UNQUOTED([PHP_HTTP_LIBIDN2_VERSION], "$IDNA_VER", [ ]) else AC_MSG_RESULT([not found]) AC_CHECK_HEADERS([unicode/uidna.h]) case $host_os in darwin*) PHP_CHECK_FUNC(uidna_IDNToASCII, icucore);; *) AC_PATH_PROG(ICU_CONFIG, icu-config, no, [$PATH:/usr/local/bin]) if test ! -x "$ICU_CONFIG"; then ICU_CONFIG="icu-config" fi AC_MSG_CHECKING([for uidna_IDNToASCII]) if ! test -x "$ICU_CONFIG"; then ICU_CONFIG=icu-config fi if $ICU_CONFIG --exists 2>/dev/null >&2; then save_LIBS=$LIBS LIBS=$($ICU_CONFIG --ldflags) AC_TRY_RUN([ #include int main(int argc, char *argv[]) { return uidna_IDNToASCII(0, 0, 0, 0, 0, 0, 0); } ], [ AC_MSG_RESULT([yes]) AC_DEFINE([HAVE_UIDNA_IDNTOASCII], [1], [ ]) LIBS=$save_LIBS PHP_EVAL_LIBLINE(`$ICU_CONFIG --ldflags`, HTTP_SHARED_LIBADD) ], [ LIBS=$save_LIBS AC_MSG_RESULT([no]) ]) fi ;; esac fi fi dnl ---- dnl ZLIB dnl ---- AC_MSG_CHECKING([for zlib.h]) ZLIB_DIR= for i in "$PHP_HTTP_ZLIB_DIR" "$PHP_ZLIB_DIR" "$PHP_ZLIB" /usr/local /usr /opt; do if test -f "$i/include/zlib.h"; then ZLIB_DIR=$i break; fi done if test "x$ZLIB_DIR" = "x"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([could not find zlib.h]) else AC_MSG_RESULT([found in $ZLIB_DIR]) AC_MSG_CHECKING([for zlib version >= 1.2.0.4]) ZLIB_VERSION=`$EGREP "define ZLIB_VERSION" $ZLIB_DIR/include/zlib.h | $SED -e 's/[[^0-9\.]]//g'` AC_MSG_RESULT([$ZLIB_VERSION]) if test `echo $ZLIB_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*1000000 + $2*10000 + $3*100 + $4}'` -lt 1020004; then AC_MSG_ERROR([zlib version greater or equal to 1.2.0.4 required]) else PHP_ADD_INCLUDE($ZLIB_DIR/include) PHP_ADD_LIBRARY_WITH_PATH(z, $ZLIB_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD) fi fi dnl ---- dnl CURL dnl ---- if test "$PHP_HTTP_LIBCURL_DIR" = "no"; then AC_DEFINE([PHP_HTTP_HAVE_CURL], [0], [ ]) else AC_MSG_CHECKING([for curl/curl.h]) CURL_DIR= for i in "$PHP_HTTP_LIBCURL_DIR" /usr/local /usr /opt; do if test -f "$i/include/curl/curl.h"; then CURL_DIR=$i break fi done if test "x$CURL_DIR" = "x"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT([found in $CURL_DIR]) AC_MSG_CHECKING([for curl-config]) CURL_CONFIG= for i in "$CURL_DIR/bin/curl-config" "$CURL_DIR/curl-config" `which curl-config`; do if test -x "$i"; then CURL_CONFIG=$i break fi done if test "x$CURL_CONFIG" = "x"; then AC_MSG_RESULT([not found]) AC_MSG_ERROR([could not find curl-config]) else AC_MSG_RESULT([found: $CURL_CONFIG]) fi dnl RHEL6: 7.19.7 dnl SUSE11: 7.19.7 dnl Debian wheezy: 7.26.0 dnl Debian sqeeze: 7.21.0 dnl Debian ancient 7.18.2 AC_MSG_CHECKING([for curl version >= 7.18.2]) CURL_VERSION=`$CURL_CONFIG --version | $SED -e 's/[[^0-9\.]]//g'` AC_MSG_RESULT([$CURL_VERSION]) if test `echo $CURL_VERSION | $SED -e 's/[[^0-9]]/ /g' | $AWK '{print $1*10000 + $2*100 + $3}'` -lt 71802; then AC_MSG_ERROR([libcurl version greater or equal to 7.18.2 required]) fi AC_MSG_CHECKING([for HTTP2 support in libcurl]) if $CURL_CONFIG --features | $EGREP -q HTTP2; then AC_MSG_RESULT([yes]) AC_DEFINE([PHP_HTTP_HAVE_HTTP2], [1], [ ]) else AC_MSG_RESULT([no]) fi dnl dnl compile tests dnl save_INCLUDES="$INCLUDES" INCLUDES= save_LIBS="$LIBS" LIBS=-lcurl save_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS `$CURL_CONFIG --cflags`" save_LDFLAGS="$LDFLAGS" LDFLAGS="$ld_runpath_switch$CURL_DIR/$PHP_LIBDIR" AC_MSG_CHECKING([for SSL support in libcurl]) CURL_SSL=`$CURL_CONFIG --feature | $EGREP SSL` CURL_SSL_LIBS="" if test "$CURL_SSL" = "SSL"; then AC_MSG_RESULT([yes]) AC_DEFINE([PHP_HTTP_HAVE_SSL], [1], [ ]) HTTP_CURL_SSL_LIB_CHECK(OpenSSL, [ AC_CHECK_HEADER([openssl/ssl.h], [ AC_CHECK_HEADER([openssl/crypto.h], [ AC_DEFINE([PHP_HTTP_HAVE_OPENSSL], [1], [ ]) CURL_SSL_LIBS="ssl crypto" ]) ]) ]) HTTP_CURL_SSL_LIB_CHECK(GnuTLS, [ AC_CHECK_HEADER([gnutls.h], [ AC_CHECK_HEADER([gcrypt.h], [ AC_DEFINE([PHP_HTTP_HAVE_GNUTLS], [1], [ ]) CURL_SSL_LIBS="gnutls gcrypt" ]) ]) ]) HTTP_CURL_SSL_LIB_CHECK(NSS, [ AC_DEFINE([PHP_HTTP_HAVE_NSS], [1], [ ]) ]) HTTP_CURL_SSL_LIB_CHECK(SecureTransport, [ AC_DEFINE([PHP_HTTP_HAVE_DARWINSSL], [1], [ ]) ]) HTTP_CURL_SSL_LIB_CHECK(GSKit, [ AC_DEFINE([PHP_HTTP_HAVE_GSKIT], [1], [ ]) ]) else dnl no CURL_SSL AC_MSG_RESULT([no]) fi AC_MSG_CHECKING([for ares support in libcurl]) AC_TRY_RUN([ #include int main(int argc, char *argv[]) { curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); if (data && data->ares && data->ares_num0) { return 0; } return 1; } ], [ AC_MSG_RESULT([yes]) AC_DEFINE([PHP_HTTP_HAVE_ARES], [1], [ ]) ], [ AC_MSG_RESULT([no]) ], [ AC_MSG_RESULT([no]) ]) AC_MSG_CHECKING([whether CURLOPT_TLSAUTH_TYPE expects CURL_TLSAUTH_SRP or literal "SRP"]) AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURL *ch = curl_easy_init(); return curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, CURL_TLSAUTH_SRP); } ], [ AC_MSG_RESULT([CURL_TLSAUTH_SRP]) AC_DEFINE([PHP_HTTP_CURL_TLSAUTH_SRP], [CURL_TLSAUTH_SRP], [ ]) AC_DEFINE([PHP_HTTP_CURL_TLSAUTH_DEF], [CURL_TLSAUTH_NONE], [ ]) ], [ AC_TRY_RUN([ #include int main(int argc, char *argv[]) { CURL *ch = curl_easy_init(); return curl_easy_setopt(ch, CURLOPT_TLSAUTH_TYPE, "SRP"); } ], [ AC_MSG_RESULT(["SRP"]) AC_DEFINE([PHP_HTTP_CURL_TLSAUTH_SRP], ["SRP"], [ ]) AC_DEFINE([PHP_HTTP_CURL_TLSAUTH_DEF], [""], [ ]) ], [ AC_MSG_RESULT([neither]) ], [ AC_MSG_RESULT([neither]) ]) ], [ AC_MSG_RESULT([neither]) ]) INCLUDES="$save_INCLUDES" LIBS="$save_LIBS" CFLAGS="$save_CFLAGS" LDFLAGS="$save_LDFLAGS" if test -n "$CURL_SSL_LIBS"; then for CURL_SSL_LIB in $CURL_SSL_LIBS; do PHP_ADD_LIBRARY_WITH_PATH([$CURL_SSL_LIB], $CURL_DIR/$PHP_LIBDIR, PHP_HTTP_SHARED_LIBADD) done fi dnl end compile tests AC_MSG_CHECKING([for bundled SSL CA info]) CURL_CAINFO= for i in `$CURL_CONFIG --ca` "/etc/ssl/certs/ca-certificates.crt" "/etc/ssl/certs/ca-bundle.crt"; do if test -f "$i"; then CURL_CAINFO="$i" break fi done if test "x$CURL_CAINFO" = "x"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT([$CURL_CAINFO]) AC_DEFINE_UNQUOTED([PHP_HTTP_CURL_CAINFO], ["$CURL_CAINFO"], [path to bundled SSL CA info]) fi PHP_ADD_INCLUDE($CURL_DIR/include) PHP_ADD_LIBRARY_WITH_PATH(curl, $CURL_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD) PHP_EVAL_LIBLINE(`$CURL_CONFIG --libs`, HTTP_SHARED_LIBADD) AC_DEFINE([PHP_HTTP_HAVE_CURL], [1], [Have libcurl support]) HTTP_HAVE_A_REQUEST_LIB=true fi fi dnl ---- dnl EVENT dnl ---- if test "$PHP_HTTP_LIBEVENT_DIR" = "no"; then AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ]) else AC_MSG_CHECKING([for event2/event.h]) EVENT_DIR= for i in "$PHP_HTTP_LIBEVENT_DIR" /usr/local /usr /opt; do if test -f "$i/include/event.h"; then EVENT_DIR=$i break fi done if test "x$EVENT_DIR" = "x"; then AC_MSG_RESULT([not found]) AC_MSG_WARN([continuing without libevent support]) AC_DEFINE([PHP_HTTP_HAVE_EVENT], [0], [ ]) else AC_MSG_RESULT([found in $EVENT_DIR]) AC_MSG_CHECKING([for libevent version, roughly]) if test -f "$EVENT_DIR/include/event2/event.h"; then EVENT_VER="`$AWK '/_EVENT_VERSION/ {gsub(/\"/,\"\",$3); print $3}' < $EVENT_DIR/include/event2/event-config.h`" AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [1], [ ]) else AC_DEFINE([PHP_HTTP_HAVE_EVENT2], [0], [ ]) if test -f "$EVENT_DIR/include/evhttp.h" && test -f "$EVENT_DIR/include/evdns.h"; then if test -f "$EVENT_DIR/include/evrpc.h"; then EVENT_VER="1.4 or greater" else EVENT_VER="1.2 or greater" fi else EVENT_VER="1.1b or lower" fi fi AC_DEFINE_UNQUOTED([PHP_HTTP_EVENT_VERSION], ["$EVENT_VER"], [ ]) AC_MSG_RESULT([$EVENT_VER]) PHP_ADD_INCLUDE($EVENT_DIR/include) PHP_ADD_LIBRARY_WITH_PATH(event, $EVENT_DIR/$PHP_LIBDIR, HTTP_SHARED_LIBADD) AC_DEFINE([PHP_HTTP_HAVE_EVENT], [1], [Have libevent support for cURL]) fi fi dnl ---- dnl RAPHF dnl ---- HTTP_HAVE_PHP_EXT([raphf], [ AC_MSG_CHECKING([for php_raphf.h]) HTTP_EXT_RAPHF_INCDIR= for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../raphf; do if test -d $i; then if test -f $i/php_raphf.h; then HTTP_EXT_RAPHF_INCDIR=$i break elif test -f $i/ext/raphf/php_raphf.h; then HTTP_EXT_RAPHF_INCDIR=$i/ext/raphf break fi fi done if test "x$HTTP_EXT_RAPHF_INCDIR" = "x"; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([$HTTP_EXT_RAPHF_INCDIR]) AC_DEFINE([PHP_HTTP_HAVE_PHP_RAPHF_H], [1], [Have ext/raphf support]) PHP_ADD_INCLUDE([$HTTP_EXT_RAPHF_INCDIR]) fi ], [ AC_MSG_ERROR([Please install pecl/raphf and activate extension=raphf.$SHLIB_DL_SUFFIX_NAME in your php.ini]) ]) dnl ---- dnl PROPRO dnl ---- HTTP_HAVE_PHP_EXT([propro], [ AC_MSG_CHECKING([for php_propro.h]) HTTP_EXT_PROPRO_INCDIR= for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../propro; do if test -d $i; then if test -f $i/php_propro.h; then HTTP_EXT_PROPRO_INCDIR=$i break elif test -f $i/ext/propro/php_propro.h; then HTTP_EXT_PROPRO_INCDIR=$i/ext/propro break fi fi done if test "x$HTTP_EXT_PROPRO_INCDIR" = "x"; then AC_MSG_ERROR([not found]) else AC_MSG_RESULT([$HTTP_EXT_PROPRO_INCDIR]) AC_DEFINE([PHP_HTTP_HAVE_PHP_PROPRO_H], [1], [Have ext/propro support]) PHP_ADD_INCLUDE([$HTTP_EXT_PROPRO_INCDIR]) fi ], [ AC_MSG_ERROR([Please install pecl/propro and activate extension=propro.$SHLIB_DL_SUFFIX_NAME in your php.ini]) ]) PHP_ARG_WITH([http-shared-deps], [whether to depend on extensions which have been built shared], [ --without-http-shared-deps HTTP: do not depend on extensions like hash and iconv (when they are built shared)], $PHP_HTTP, $PHP_HTTP) dnl ---- dnl HASH dnl ---- HTTP_HAVE_PHP_EXT([hash], [ AC_MSG_CHECKING([for php_hash.h]) HTTP_EXT_HASH_INCDIR= for i in `echo $INCLUDES | $SED -e's/-I//g'` $abs_srcdir ../hash; do if test -d $i; then if test -f $i/php_hash.h; then HTTP_EXT_HASH_INCDIR=$i break elif test -f $i/ext/hash/php_hash.h; then HTTP_EXT_HASH_INCDIR=$i/ext/hash break fi fi done if test "x$HTTP_EXT_HASH_INCDIR" = "x"; then AC_MSG_RESULT([not found]) else AC_MSG_RESULT([$HTTP_EXT_HASH_INCDIR]) AC_DEFINE([PHP_HTTP_HAVE_PHP_HASH_H], [1], [Have ext/hash support]) PHP_ADD_INCLUDE([$HTTP_EXT_HASH_INCDIR]) fi ]) dnl ---- dnl ICONV dnl ---- HTTP_HAVE_PHP_EXT([iconv]) dnl ---- dnl DONE dnl ---- PHP_SUBST([HTTP_SHARED_LIBADD]) PHP_HTTP_SRCDIR=PHP_EXT_SRCDIR(http) PHP_HTTP_BUILDDIR=PHP_EXT_BUILDDIR(http) PHP_ADD_INCLUDE($PHP_HTTP_SRCDIR/src) PHP_ADD_BUILD_DIR($PHP_HTTP_BUILDDIR/src) PHP_HTTP_HEADERS=`(cd $PHP_HTTP_SRCDIR/src && echo *.h)` PHP_HTTP_SOURCES=`(cd $PHP_HTTP_SRCDIR && echo src/*.c)` PHP_NEW_EXTENSION(http, $PHP_HTTP_SOURCES, $ext_shared) PHP_INSTALL_HEADERS(ext/http, php_http.h $PHP_HTTP_HEADERS) HTTP_SHARED_DEP([hash]) HTTP_SHARED_DEP([iconv]) PHP_ADD_EXTENSION_DEP([http], [raphf], true) PHP_ADD_EXTENSION_DEP([http], [propro], true) PHP_SUBST(PHP_HTTP_HEADERS) PHP_SUBST(PHP_HTTP_SOURCES) PHP_SUBST(PHP_HTTP_SRCDIR) PHP_SUBST(PHP_HTTP_BUILDDIR) PHP_ADD_MAKEFILE_FRAGMENT AC_DEFINE([HAVE_HTTP], [1], [Have extended HTTP support]) if $HTTP_HAVE_A_REQUEST_LIB; then AC_DEFINE([PHP_HTTP_HAVE_CLIENT], [1], [Have HTTP client support]) fi fi pecl_http-3.0.1/config.w320000644000175000001440000001005612667772426014170 0ustar mikeusers// config.w32 for pecl/http // $Id$ ARG_ENABLE("http", "whether to enable extended HTTP support", "no"); function check_for_main_ext(ext, header) { if (!header) { header = "php_"+ ext +".h"; } /* When in configure, we're always in the root of PHP source */ var ext_path = "ext\\" + ext; STDOUT.Write("Checking for ext/"+ ext +" ... "); if (FSO.FileExists(ext_path + "\\" + header)) { STDOUT.WriteLine(ext_path); return ext_path; } STDOUT.WriteLine(""); return false; } function check_for_pecl_ext(ext, header) { if (!header) { header = "php_"+ ext +".h"; } var g; var s = ext +"\\"+ header; STDOUT.Write("Checking for pecl/"+ ext +" ... "); if ( (g = glob(configure_module_dirname +"\\..\\"+ s)) || (g = glob(configure_module_dirname +"\\..\\..\\..\\pecl\\"+ s))) { var f = g[0].substr(0, g[0].length - header.length - 1); STDOUT.WriteLine(f); return f; } STDOUT.WriteLine(""); return false; } if (PHP_HTTP != "no") { var PHP_HTTP_SRC_ARRAY = glob(configure_module_dirname + "/src/*.c"); var PHP_HTTP_SOURCES=""; for (var i=0; i$@ <$< $(all_targets): http-build-headers clean: http-clean-headers .PHONY: http-build-headers http-build-headers: $(PHP_HTTP_HEADERS) .PHONY: http-clean-headers http-clean-headers: -rm -f $(PHP_HTTP_HEADERS) pecl_http-3.0.1/php_http.h0000644000175000001440000000203512667772426014363 0ustar mikeusers/* +--------------------------------------------------------------------+ | 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_EXT_HTTP_H #define PHP_EXT_HTTP_H #define PHP_PECL_HTTP_VERSION "3.0.1" extern zend_module_entry http_module_entry; #define phpext_http_ptr &http_module_entry extern int http_module_number; #endif /* PHP_EXT_HTTP_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 */