#include "php_http_message_object.h"
#include "php_http_response_object.h"
#include "php_http_request_object.h"
+#include "php_http_requestpool_object.h"
#include "php_http_exception_object.h"
#ifdef ZEND_ENGINE_2
+#include "missing.h"
+
ZEND_EXTERN_MODULE_GLOBALS(http)
/* {{{ HttpResponse */
}
/* }}} */
-/* {{{ proto bool HttpResponse::send()
+/* {{{ proto bool HttpResponse::send([bool clean_ob = true])
*
* Finally send the entity.
*
*/
PHP_METHOD(HttpResponse, send)
{
+ zend_bool clean_ob = 1;
zval *do_cache, *do_gzip;
getObject(http_response_object, obj);
- NO_ARGS;
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|b", &clean_ob)) {
+ RETURN_FALSE;
+ }
do_cache = GET_PROP(obj, cache);
do_gzip = GET_PROP(obj, gzip);
+ if (clean_ob) {
+ /* interrupt on-the-fly etag generation */
+ HTTP_G(etag).started = 0;
+ /* discard previous output buffers */
+ php_end_ob_buffers(0 TSRMLS_CC);
+ }
+
/* gzip */
if (Z_LVAL_P(do_gzip)) {
php_start_ob_buffer_named("ob_gzhandler", 0, 1 TSRMLS_CC);
/* {{{ HttpMessage */
-/* {{{ proto static HttpMessage HttpMessage::fromString(string raw_message)
- *
- * Create an HttpMessage object from a string.
- */
-PHP_METHOD(HttpMessage, fromString)
-{
- char *string = NULL;
- int length = 0;
- http_message *msg = NULL;
- http_message_object obj;
-
- if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
- RETURN_NULL();
- }
-
- if (!(msg = http_message_parse(string, length))) {
- RETURN_NULL();
- }
-
- Z_TYPE_P(return_value) = IS_OBJECT;
- return_value->value.obj = http_message_object_from_msg(msg);
-}
-/* }}} */
-
/* {{{ proto void HttpMessage::__construct([string message])
*
* Instantiate a new HttpMessage object.
}
/* }}} */
+/* {{{ proto static HttpMessage HttpMessage::fromString(string raw_message)
+ *
+ * Create an HttpMessage object from a string.
+ */
+PHP_METHOD(HttpMessage, fromString)
+{
+ char *string = NULL;
+ int length = 0;
+ http_message *msg = NULL;
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &string, &length)) {
+ RETURN_NULL();
+ }
+
+ if (!(msg = http_message_parse(string, length))) {
+ RETURN_NULL();
+ }
+
+ Z_TYPE_P(return_value) = IS_OBJECT;
+ return_value->value.obj = http_message_object_from_msg(msg);
+}
+/* }}} */
+
/* {{{ proto string HttpMessage::getBody()
*
* Get the body of the parsed Message.
NO_ARGS;
IF_RETVAL_USED {
- zval *uri;
getObject(http_message_object, obj);
if (!HTTP_MSG_TYPE(REQUEST, obj->message)) {
PHP_METHOD(HttpMessage, setHttpVersion)
{
char v[4];
- zval *zv, *version;
+ zval *zv;
getObject(http_message_object, obj);
if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z/", &zv)) {
}
/* }}} */
+/* {{{ proto bool HttpRequest::setPostFiles()
+ *
+ * Set files to post.
+ * Overwrites previously set post files.
+ * Affects only POST requests.
+ */
+PHP_METHOD(HttpRequest, setPostFiles)
+{
+ zval *files, *pFiles;
+ getObject(http_request_object, obj);
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &files)) {
+ RETURN_FALSE;
+ }
+
+ pFiles = GET_PROP(obj, postFiles);
+ zend_hash_clean(Z_ARRVAL_P(pFiles));
+ array_copy(files, pFiles);
+
+ RETURN_TRUE;
+}
+/* }}} */
+
/* {{{ proto array HttpRequest::getPostFiles()
*
* Get all previously added POST files.
}
/* }}} */
+/* {{{ proto bool HttpRequest::SetPutFile(string file)
+ *
+ * Set file to put.
+ * Affects only PUT requests.
+ */
+PHP_METHOD(HttpRequest, setPutFile)
+{
+ char *file;
+ int file_len;
+ getObject(http_request_object, obj);
+
+ if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &file_len)) {
+ RETURN_FALSE;
+ }
+
+ UPD_PROP(obj, string, putFile, file);
+ RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string HttpRequest::getPutFile()
+ *
+ * Get previously set put file.
+ */
+PHP_METHOD(HttpRequest, getPutFile)
+{
+ NO_ARGS;
+
+ IF_RETVAL_USED {
+ zval *putfile;
+ getObject(http_request_object, obj);
+
+ putfile = GET_PROP(obj, putFile);
+ RETVAL_STRINGL(Z_STRVAL_P(putfile), Z_STRLEN_P(putfile), 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto void HttpRequest::unsetPutFile()
+ *
+ * Unset file to put.
+ * Affects only PUT requests.
+ */
+PHP_METHOD(HttpRequest, unsetPutFile)
+{
+ getObject(http_request_object, obj);
+
+ NO_ARGS;
+
+ UPD_PROP(obj, string, putFile, "");
+}
+/* }}} */
+
/* {{{ proto array HttpRequest::getResponseData()
*
* Get all response data after the request has been sent.
PHP_METHOD(HttpRequest, send)
{
STATUS status = FAILURE;
- zval *meth, *URL, *qdata, *opts, *info, *resp;
- char *request_uri;
+ http_request_body body = {0};
getObject(http_request_object, obj);
NO_ARGS;
SET_EH_THROW_HTTP();
- if ((!obj->ch) && (!(obj->ch = curl_easy_init()))) {
- http_error(E_WARNING, HTTP_E_CURL, "Could not initilaize curl");
+ if (obj->pool) {
+ http_error(E_WARNING, HTTP_E_CURL, "You cannot call HttpRequest::send() while attached to an HttpRequestPool");
RETURN_FALSE;
}
- meth = GET_PROP(obj, method);
- URL = GET_PROP(obj, url);
- qdata = GET_PROP(obj, queryData);
- opts = GET_PROP(obj, options);
- info = GET_PROP(obj, responseInfo);
- resp = GET_PROP(obj, responseData);
-
- // HTTP_URI_MAXLEN+1 long char *
- if (!(request_uri = http_absolute_uri_ex(Z_STRVAL_P(URL), Z_STRLEN_P(URL), NULL, 0, NULL, 0, 0))) {
- RETURN_FALSE;
+ if (SUCCESS == (status = http_request_object_requesthandler(obj, getThis(), &body))) {
+ status = http_request_exec(obj->ch, NULL);
}
+ http_request_body_dtor(&body);
- if (Z_STRLEN_P(qdata) && (strlen(request_uri) < HTTP_URI_MAXLEN)) {
- if (!strchr(request_uri, '?')) {
- strcat(request_uri, "?");
- } else {
- strcat(request_uri, "&");
- }
- strncat(request_uri, Z_STRVAL_P(qdata), HTTP_URI_MAXLEN - strlen(request_uri));
+ /* final data handling */
+ if (SUCCESS == status) {
+ status = http_request_object_responsehandler(obj, getThis());
}
- switch (Z_LVAL_P(meth))
- {
- case HTTP_GET:
- case HTTP_HEAD:
- status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, NULL, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
- break;
+ SET_EH_NORMAL();
+ RETURN_SUCCESS(status);
+}
+/* }}} */
- case HTTP_PUT:
- {
- http_request_body body;
- php_stream *stream;
- php_stream_statbuf ssb;
- zval *file = GET_PROP(obj, putFile);
-
- if ( (stream = php_stream_open_wrapper(Z_STRVAL_P(file), , "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL)) &&
- !php_stream_stat(stream, &ssb)) {
- body.type = HTTP_REQUEST_BODY_UPLOADFILE;
- body.data = stream;
- body.size = ssb.sb.st_size;
-
- status = http_put_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
- http_request_body_dtor(&body);
- } else {
- status = FAILURE;
- }
- }
- break;
+/* {{{ HttpRequestPool */
- case HTTP_POST:
- {
- http_request_body body;
- zval *fields = GET_PROP(obj, postFields), *files = GET_PROP(obj, postFiles);
+/* {{{ proto void HttpRequestPool::__construct()
+ *
+ * Instantiate a new HttpRequestPool object.
+ */
+PHP_METHOD(HttpRequestPool, __construct)
+{
+ NO_ARGS;
+}
+/* }}} */
- if (SUCCESS == (status = http_request_body_fill(&body, Z_ARRVAL_P(fields), Z_ARRVAL_P(files)))) {
- status = http_post_ex(obj->ch, request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
- http_request_body_dtor(&body);
- }
- }
- break;
+/* {{{ proto void HttpRequestPool::__destruct()
+ *
+ * Clean up HttpRequestPool object.
+ */
+PHP_METHOD(HttpRequestPool, __destruct)
+{
+ getObject(http_requestpool_object, obj);
- default:
- {
- http_request_body body;
- zval *post = GET_PROP(obj, postData);
+ NO_ARGS;
- body.type = HTTP_REQUEST_BODY_CSTRING;
- body.data = Z_STRVAL_P(post);
- body.size = Z_STRLEN_P(post);
+ http_request_pool_detach_all(&obj->pool);
+}
+/* }}} */
- status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response);
- }
- break;
+/* {{{ proto void HttpRequestPool::reset()
+ *
+ * Detach all attached HttpRequest objects.
+ */
+PHP_METHOD(HttpRequestPool, reset)
+{
+ getObject(http_requestpool_object, obj);
+
+ NO_ARGS;
+
+ http_request_pool_detach_all(&obj->pool);
+}
+
+/* {{{ proto bool HttpRequestPool::attach(HttpRequest request)
+ *
+ * Attach an HttpRequest object to this HttpRequestPool.
+ * NOTE: set all options prior attaching!
+ */
+PHP_METHOD(HttpRequestPool, attach)
+{
+ zval *request;
+ STATUS status = FAILURE;
+ getObject(http_requestpool_object, obj);
+
+ SET_EH_THROW_HTTP();
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
+ status = http_request_pool_attach(&obj->pool, request);
+ }
+ SET_EH_NORMAL();
+ RETURN_SUCCESS(status);
+}
+/* }}} */
+
+/* {{{ proto bool HttpRequestPool::detach(HttpRequest request)
+ *
+ * Detach an HttpRequest object from this HttpRequestPool.
+ */
+PHP_METHOD(HttpRequestPool, detach)
+{
+ zval *request;
+ STATUS status = FAILURE;
+ getObject(http_requestpool_object, obj);
+
+ SET_EH_THROW_HTTP();
+ if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &request, http_request_object_ce)) {
+ status = http_request_pool_detach(&obj->pool, request);
}
+ SET_EH_NORMAL();
+ RETURN_SUCCESS(status);
+}
+/* }}} */
- efree(request_uri);
+/* {{{ proto bool HttpRequestPool::send()
+ *
+ * Send all attached HttpRequest objects in parallel.
+ */
+PHP_METHOD(HttpRequestPool, send)
+{
+ getObject(http_requestpool_object, obj);
- /* final data handling */
- if (status == SUCCESS) {
- http_message *msg;
+ NO_ARGS;
+
+ RETURN_SUCCESS(http_request_pool_send(&obj->pool));
+}
+/* }}} */
+
+/* {{{ proto protected bool HttpRequestPool::socketSend()
+ *
+ * Usage:
+ * <pre>
+ * <?php
+ * while ($pool->socketSend()) {
+ * do_something_else();
+ * if (!$pool->socketSelect()) {
+ * die('Socket error');
+ * }
+ * }
+ * $pool->socketRead();
+ * ?>
+ * </pre>
+ */
+PHP_METHOD(HttpRequestPool, socketSend)
+{
+ getObject(http_requestpool_object, obj);
- if (msg = http_message_parse(PHPSTR_VAL(&obj->response), PHPSTR_LEN(&obj->response))) {
- zval *headers, *message;
- char *body;
- size_t body_len;
+ NO_ARGS;
- UPD_PROP(obj, long, responseCode, msg->info.response.code);
+ RETURN_BOOL(0 < http_request_pool_perform(&obj->pool));
+}
+/* }}} */
- MAKE_STD_ZVAL(headers)
- array_init(headers);
+/* {{{ proto protected bool HttpRequestPool::socketSelect()
+ *
+ * See HttpRequestPool::socketSend().
+ */
+PHP_METHOD(HttpRequestPool, socketSelect)
+{
+ getObject(http_requestpool_object, obj);
- zend_hash_copy(Z_ARRVAL_P(headers), &msg->hdrs, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
- phpstr_data(PHPSTR(msg), &body, &body_len);
+ NO_ARGS;
- add_assoc_zval(resp, "headers", headers);
- add_assoc_stringl(resp, "body", body, body_len, 0);
+ RETURN_SUCCESS(http_request_pool_select(&obj->pool));
+}
+/* }}} */
- message = GET_PROP(obj, responseMessage);
- zval_dtor(message);
- Z_TYPE_P(message) = IS_OBJECT;
- message->value.obj = http_message_object_from_msg(msg);
- SET_PROP(obj, responseMessage, message);
- } else {
- status = FAILURE;
- }
- }
+/* {{{ proto protected void HttpRequestPool::socketRead()
+ *
+ * See HttpRequestPool::socketSend().
+ */
+PHP_METHOD(HttpRequestPool, socketRead)
+{
+ getObject(http_requestpool_object, obj);
- SET_EH_NORMAL();
- RETURN_SUCCESS(status);
+ NO_ARGS;
+
+ zend_llist_apply(&obj->pool.handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC);
}
/* }}} */
+
+/* }}} */
+
/* }}} */
#endif /* HTTP_HAVE_CURL */