http_message_object_handlers.read_property = http_message_object_read_prop;
http_message_object_handlers.write_property = http_message_object_write_prop;
http_message_object_handlers.get_properties = http_message_object_get_props;
+ http_message_object_handlers.get_property_ptr_ptr = NULL;
}
zend_object_value _http_message_object_new(zend_class_entry *ce TSRMLS_DC)
http_message *msg = obj->message;
zval *return_value;
- /* tmp var */
- ALLOC_ZVAL(return_value);
+ return_value = &EG(uninitialized_zval);
return_value->refcount = 0;
+ return_value->is_ref = 0;
+#if 0
+ fprintf(stderr, "Read HttpMessage::$%s\n", Z_STRVAL_P(member));
+#endif
if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
return EG(uninitialized_zval_ptr);
break;
case HTTP_MSG_PROPHASH_HEADERS:
- array_init(return_value);
- zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ /* This is needed for situations like
+ * $this->headers['foo'] = 'bar';
+ */
+ if (type == BP_VAR_W) {
+ return_value->refcount = 1;
+ return_value->is_ref = 1;
+ Z_TYPE_P(return_value) = IS_ARRAY;
+ Z_ARRVAL_P(return_value) = &msg->hdrs;
+ } else {
+ array_init(return_value);
+ zend_hash_copy(Z_ARRVAL_P(return_value), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
+ }
break;
case HTTP_MSG_PROPHASH_PARENT_MESSAGE:
getObjectEx(http_message_object, obj, object);
http_message *msg = obj->message;
+#if 0
+ fprintf(stderr, "Write HttpMessage::$%s\n", Z_STRVAL_P(member));
+#endif
if (!EG(scope) || !instanceof_function(EG(scope), obj->zo.ce TSRMLS_CC)) {
zend_error(E_WARNING, "Cannot access protected property %s::$%s", obj->zo.ce->name, Z_STRVAL_P(member));
}
IF_RETVAL_USED {
char ver[4] = {0};
- float version;
+ double version;
getObject(http_message_object, obj);
switch (obj->message->type)
default:
RETURN_NULL();
}
- sprintf(ver, "%1.1f", version);
+ sprintf(ver, "%1.1lf", version);
RETURN_STRINGL(ver, 3, 1);
}
}
}
convert_to_double(zv);
- sprintf(v, "%1.1f", Z_DVAL_P(zv));
+ sprintf(v, "%1.1lf", Z_DVAL_P(zv));
if (strcmp(v, "1.0") && strcmp(v, "1.1")) {
http_error_ex(E_WARNING, HTTP_E_PARAM, "Invalid HTTP protocol version (1.0 or 1.1): %s", v);
RETURN_FALSE;
}
if (HTTP_MSG_TYPE(RESPONSE, obj->message)) {
- obj->message->info.response.http_version = (float) Z_DVAL_P(zv);
+ obj->message->info.response.http_version = Z_DVAL_P(zv);
} else {
- obj->message->info.request.http_version = (float) Z_DVAL_P(zv);
+ obj->message->info.request.http_version = Z_DVAL_P(zv);
}
RETURN_TRUE;
}
{
zend_bool free_pool;
#if HTTP_DEBUG_REQPOOLS
- fprintf(stderr, "Initializing request pool\n");
+ fprintf(stderr, "Initializing request pool %p\n", pool);
#endif
if ((free_pool = (!pool))) {
pool = emalloc(sizeof(http_request_pool));
{
getObjectEx(http_request_object, req, request);
#if HTTP_DEBUG_REQPOOLS
- fprintf(stderr, "Attaching request %p to pool %p\n", req, pool);
+ fprintf(stderr, "Attaching HttpRequest(#%d) %p to pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
#endif
if (req->pool) {
- http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is already member of an HttpRequestPool");
+ http_error_ex(E_WARNING, HTTP_E_CURL, "HttpRequest object(#%d) is already member of %s HttpRequestPool", Z_OBJ_HANDLE_P(request), req->pool == pool ? "this" : "another");
} else {
- CURLMcode code;
http_request_body *body = http_request_body_new();
zval *info = GET_PROP_EX(req, request, responseInfo);
if (SUCCESS != http_request_object_requesthandler(req, request, body)) {
http_error_ex(E_WARNING, HTTP_E_CURL, "Could not initialize HttpRequest object for attaching to the HttpRequestPool");
} else {
- code = curl_multi_add_handle(pool->ch, req->ch);
+ CURLMcode code = curl_multi_add_handle(pool->ch, req->ch);
+
if ((CURLM_OK != code) && (CURLM_CALL_MULTI_PERFORM != code)) {
http_error_ex(E_WARNING, HTTP_E_CURL, "Could not attach HttpRequest object to the HttpRequestPool: %s", curl_multi_strerror(code));
} else {
req->pool = pool;
+
zend_llist_add_element(&pool->handles, &request);
zend_llist_add_element(&pool->bodies, &body);
+
zval_add_ref(&request);
+ zend_objects_store_add_ref(request TSRMLS_CC);
+
+#if HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "> %d HttpRequests attached to pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
return SUCCESS;
}
}
{
getObjectEx(http_request_object, req, request);
#if HTTP_DEBUG_REQPOOLS
- fprintf(stderr, "Detaching request %p from pool %p\n", req, pool);
+ fprintf(stderr, "Detaching HttpRequest(#%d) %p from pool %p\n", Z_OBJ_HANDLE_P(request), req, pool);
#endif
- if (req->pool != pool) {
- http_error(E_WARNING, HTTP_E_CURL, "HttpRequest object is not attached to this HttpRequestPool");
+ if (!req->pool) {
+ /* not attached to any pool */
+#if HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "HttpRequest object(#%d) %p is not attached to any HttpRequestPool\n", Z_OBJ_HANDLE_P(request), req);
+#endif
+ } else if (req->pool != pool) {
+ http_error_ex(E_WARNING, HTTP_E_CURL, "HttpRequest object(#%d) is not attached to this HttpRequestPool", Z_OBJ_HANDLE_P(request));
} else {
CURLMcode code;
+ req->pool = NULL;
+ zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
+#if HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "> %d HttpRequests remaining in pool %p\n", zend_llist_count(&pool->handles), pool);
+#endif
if (CURLM_OK != (code = curl_multi_remove_handle(pool->ch, req->ch))) {
http_error_ex(E_WARNING, HTTP_E_CURL, "Could not detach HttpRequest object from the HttpRequestPool: %s", curl_multi_strerror(code));
} else {
- req->pool = NULL;
- zend_llist_del_element(&pool->handles, request, http_request_pool_compare_handles);
return SUCCESS;
}
}
#endif
while (http_request_pool_perform(pool)) {
#if HTTP_DEBUG_REQPOOLS
- fprintf(stderr, "%d unfinished requests of pool %p remaining\n", pool->unfinished, pool);
+ fprintf(stderr, "> %d unfinished requests of pool %p remaining\n", pool->unfinished, pool);
#endif
if (SUCCESS != http_request_pool_select(pool)) {
http_error(E_WARNING, HTTP_E_CURL, "Socket error");
return FAILURE;
}
}
+#if HTTP_DEBUG_REQPOOLS
+ fprintf(stderr, "Finished sending %d HttpRequests of pool %p (still unfinished: %d)\n", zend_llist_count(&pool->handles), pool, pool->unfinished);
+#endif
zend_llist_apply(&pool->handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
return SUCCESS;
}
{
getObjectEx(http_request_object, obj, *req);
#if HTTP_DEBUG_REQPOOLS
- fprintf(stderr, "Fetching data from request %p of pool %p\n", obj, obj->pool);
+ fprintf(stderr, "Fetching data from HttpRequest(#%d) %p of pool %p\n", Z_OBJ_HANDLE_PP(req), obj, obj->pool);
#endif
http_request_object_responsehandler(obj, *req);
}
/* {{{ static int http_request_pool_compare_handles(void *, void *) */
static int http_request_pool_compare_handles(void *h1, void *h2)
{
- return ((*((zval **) h1)) == ((zval *) h2));
+ int match = (Z_OBJ_HANDLE_PP((zval **) h1) == Z_OBJ_HANDLE_P((zval *) h2));
+#if HTTP_DEBUG_REQPOOLS
+ /* if(match) fprintf(stderr, "OK\n"); */
+#endif
+ return match;
}
/* }}} */
#include "php_http_request_object.h"
#include "php_http_exception_object.h"
+#include "zend_interfaces.h"
+
#ifdef PHP_WIN32
# include <winsock2.h>
#endif
HTTP_EMPTY_ARGS(socketSelect, 0);
HTTP_EMPTY_ARGS(socketRead, 0);
+HTTP_EMPTY_ARGS(valid, 0);
+HTTP_EMPTY_ARGS(current, 1);
+HTTP_EMPTY_ARGS(key, 0);
+HTTP_EMPTY_ARGS(next, 0);
+HTTP_EMPTY_ARGS(rewind, 0);
#define http_requestpool_object_declare_default_properties() _http_requestpool_object_declare_default_properties(TSRMLS_C)
static inline void _http_requestpool_object_declare_default_properties(TSRMLS_D);
HTTP_REQPOOL_ME(socketSelect, ZEND_ACC_PROTECTED)
HTTP_REQPOOL_ME(socketRead, ZEND_ACC_PROTECTED)
+ /* implements Interator */
+ HTTP_REQPOOL_ME(valid, ZEND_ACC_PUBLIC)
+ HTTP_REQPOOL_ME(current, ZEND_ACC_PUBLIC)
+ HTTP_REQPOOL_ME(key, ZEND_ACC_PUBLIC)
+ HTTP_REQPOOL_ME(next, ZEND_ACC_PUBLIC)
+ HTTP_REQPOOL_ME(rewind, ZEND_ACC_PUBLIC)
+
{NULL, NULL, NULL}
};
static zend_object_handlers http_requestpool_object_handlers;
void _http_requestpool_object_init(INIT_FUNC_ARGS)
{
HTTP_REGISTER_CLASS_EX(HttpRequestPool, http_requestpool_object, NULL, 0);
+ zend_class_implements(http_requestpool_object_ce TSRMLS_CC, 1, zend_ce_iterator);
}
zend_object_value _http_requestpool_object_new(zend_class_entry *ce TSRMLS_DC)
o->zo.ce = ce;
http_request_pool_init(&o->pool);
+ o->iterator.pos = 0;
ALLOC_HASHTABLE(OBJ_PROP(o));
zend_hash_init(OBJ_PROP(o), 0, NULL, ZVAL_PTR_DTOR, 0);
* Example:
* <pre>
* <?php
- * $urls = array('www.php.net', 'pecl.php.net', 'pear.php.net')
- * $pool = new HttpRequestPool;
- * foreach ($urls as $url) {
- * $req[$url] = new HttpRequest("http://$url", HTTP_HEAD);
- * $pool->attach($req[$url]);
- * }
+ * try {
+ * $pool = new HttpRequestPool(
+ * new HttpRequest('http://www.google.com/', HTTP_HEAD),
+ * new HttpRequest('http://www.php.net/', HTTP_HEAD)
+ * );
* $pool->send();
- * foreach ($urls as $url) {
- * printf("%s (%s) is %s\n",
- * $url, $req[$url]->getResponseInfo('effective_url'),
- * $r->getResponseCode() == 200 ? 'alive' : 'not alive'
+ * foreach($pool as $request) {
+ * printf("%s is %s (%d)\n",
+ * $request->getResponseInfo('effective_url'),
+ * $request->getResponseCode() ? 'alive' : 'not alive',
+ * $request->getResponseCode()
* );
* }
+ * } catch (HttpException $e) {
+ * echo $e;
+ * }
* ?>
* </pre>
*/
}
/* }}} */
+/* implements Iterator */
+
+/* {{{ proto bool HttpRequestPool::valid()
+ */
+PHP_METHOD(HttpRequestPool, valid)
+{
+ NO_ARGS;
+
+ IF_RETVAL_USED {
+ getObject(http_requestpool_object, obj);
+ RETURN_BOOL(obj->iterator.pos < zend_llist_count(&obj->pool.handles));
+ }
+}
+/* }}} */
+
+/* {{{ proto HttpRequest HttpRequestPool::current()
+ */
+PHP_METHOD(HttpRequestPool, current)
+{
+ NO_ARGS;
+
+ IF_RETVAL_USED {
+ long pos = 0;
+ zval **current = NULL;
+ zend_llist_position lpos;
+ getObject(http_requestpool_object, obj);
+
+ if (obj->iterator.pos < zend_llist_count(&obj->pool.handles)) {
+ for ( current = zend_llist_get_first_ex(&obj->pool.handles, &lpos);
+ current && obj->iterator.pos != pos++;
+ current = zend_llist_get_next_ex(&obj->pool.handles, &lpos));
+ if (current) {
+ RETURN_OBJECT(*current);
+ }
+ }
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto long HttpRequestPool::key()
+ */
+PHP_METHOD(HttpRequestPool, key)
+{
+ NO_ARGS;
+
+ IF_RETVAL_USED {
+ getObject(http_requestpool_object, obj);
+ RETURN_LONG(obj->iterator.pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto void HttpRequestPool::next()
+ */
+PHP_METHOD(HttpRequestPool, next)
+{
+ NO_ARGS {
+ getObject(http_requestpool_object, obj);
+ ++(obj->iterator.pos);
+ }
+}
+/* }}} */
+
+/* {{{ proto void HttpRequestPool::rewind()
+ */
+PHP_METHOD(HttpRequestPool, rewind)
+{
+ NO_ARGS {
+ getObject(http_requestpool_object, obj);
+ obj->iterator.pos = 0;
+ }
+}
+/* }}} */
+
#endif /* ZEND_ENGINE_2 && HTTP_HAVE_CURL */
/*
*/
PHP_METHOD(HttpResponse, setData)
{
- zval *the_data, **data;
+ zval *the_data;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_data)) {
RETURN_FALSE;
*/
PHP_METHOD(HttpResponse, send)
{
- zval *do_cache, *do_gzip, *sent;
+ zval *sent;
zend_bool clean_ob = 1;
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) {
/* caching */
if (Z_LVAL_P(GET_STATIC_PROP(cache))) {
- char *cc_hdr;
- int cc_len;
zval *cctl, *etag, *lmod;
etag = GET_STATIC_PROP(eTag);
typedef struct {
zend_object zo;
http_request_pool pool;
+ struct {
+ long pos;
+ } iterator;
} http_requestpool_object;
extern zend_class_entry *http_requestpool_object_ce;
PHP_METHOD(HttpRequestPool, socketSend);
PHP_METHOD(HttpRequestPool, socketSelect);
PHP_METHOD(HttpRequestPool, socketRead);
+PHP_METHOD(HttpRequestPool, valid);
+PHP_METHOD(HttpRequestPool, current);
+PHP_METHOD(HttpRequestPool, key);
+PHP_METHOD(HttpRequestPool, next);
+PHP_METHOD(HttpRequestPool, rewind);
#endif
#endif
# define DCL_STATIC_PROP_Z(a, n, v) zend_declare_property(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a | ZEND_ACC_STATIC) TSRMLS_CC)
# define DCL_STATIC_PROP_N(a, n) zend_declare_property_null(ce, (#n), sizeof(#n), (ZEND_ACC_ ##a | ZEND_ACC_STATIC) TSRMLS_CC)
# define GET_STATIC_PROP_EX(ce, n) zend_std_get_static_property(ce, (#n), sizeof(#n), 0 TSRMLS_CC)
+#ifdef zend_update_class_constants
# define USE_STATIC_PROP_EX(ce) zend_update_class_constants(ce TSRMLS_CC)
+#else
+# define USE_STATIC_PROP_EX(ce)
+#endif
# define SET_STATIC_PROP_EX(ce, n, v) \
{ \
int refcount; \
<?php
include 'skip.inc';
checkver(5);
-checkurl('http://www.php.net');
+checkurl('www.php.net');
+checkurl('pear.php.net');
+checkurl('pecl.php.net');
?>
--FILE--
<?php
-$urls = array(
- 'http://www.php.net',
- 'http://pear.php.net',
- 'http://pecl.php.net'
+$pool = new HttpRequestPool(
+ new HttpRequest('http://www.php.net/', HTTP_HEAD),
+ new HttpRequest('http://pear.php.net/', HTTP_HEAD),
+ new HttpRequest('http://pecl.php.net/', HTTP_HEAD)
);
-$pool = new HttpRequestPool;
-foreach ($urls as $url) {
- $pool->attach($reqs[] = new HttpRequest($url, HTTP_HEAD));
-}
$pool->send();
-foreach ($reqs as $req) {
- echo $req->getResponseInfo('effective_url'), '=',
+foreach ($pool as $req) {
+ echo $req->getUrl(), '=',
$req->getResponseCode(), ':',
$req->getResponseMessage()->getResponseCode(), "\n";
- $pool->detach($req);
- $pool->attach($req);
- $pool->detach($req);
- $pool->attach($req);
- $pool->detach($req);
- $pool->attach($req);
- $pool->detach($req);
- $pool->attach($req);
- $req->getResponseMessage()->getResponseCode();
- $req->getResponseMessage()->getResponseCode();
- $req->getResponseMessage()->getResponseCode();
- $req->getResponseMessage()->getResponseCode();
}
-$pool->send();
-$pool->reset();
-$pool->attach($req);
echo "Done\n";
?>
--EXPECTF--
-Content-type: text/html
-X-Powered-By: PHP/%s
-
-http://www.php.net/=200:200
+%shttp://www.php.net/=200:200
http://pear.php.net/=200:200
http://pecl.php.net/=200:200
Done
<?php
include 'skip.inc';
checkver(5);
-checkurl('http://www.google.com');
+checkurl('www.google.com');
?>
--FILE--
<?php
int(501)
int(501)
bool(true)
+
<?php
include 'skip.inc';
checkver(5);
-checkurl('http://arweb.info');
+checkurl('arweb.info');
?>
--FILE--
<?php
X-Powered-By: PHP/%s
string(10) "1234567890"
+
--TEST--
HttpResponse - send gzipped file
--SKIPIF--
-<?php
+<?php
include 'skip.inc';
checkver(5);
checkcgi();
Content-Encoding: gzip
Vary: Accept-Encoding
-%s
\ No newline at end of file
+%s