X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_methods.c;h=c18e5aec630aa7603f5e678ab23296862ed82b81;hp=322836e53685c5fd8334cca47d47df8ce3bc491d;hb=e47ee304be6758fbbfd238476f8a6bda9090fe12;hpb=4f5d70d375dac27459a80c1e5271697c1f46c675 diff --git a/http_methods.c b/http_methods.c index 322836e..c18e5ae 100644 --- a/http_methods.c +++ b/http_methods.c @@ -27,6 +27,7 @@ #include "php_http_api.h" #include "php_http_cache_api.h" #include "php_http_request_api.h" +#include "php_http_request_pool_api.h" #include "php_http_date_api.h" #include "php_http_headers_api.h" #include "php_http_message_api.h" @@ -36,6 +37,7 @@ #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 @@ -507,7 +509,7 @@ PHP_METHOD(HttpResponse, getFile) } /* }}} */ -/* {{{ proto bool HttpResponse::send() +/* {{{ proto bool HttpResponse::send([bool clean_ob = true]) * * Finally send the entity. * @@ -524,14 +526,24 @@ PHP_METHOD(HttpResponse, getFile) */ 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); @@ -622,29 +634,6 @@ PHP_METHOD(HttpResponse, send) /* {{{ 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; - - 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. @@ -669,6 +658,29 @@ PHP_METHOD(HttpMessage, __construct) } /* }}} */ +/* {{{ 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. @@ -1121,7 +1133,7 @@ PHP_METHOD(HttpRequest, __destruct) PHP_METHOD(HttpRequest, setOptions) { char *key = NULL; - long idx = 0; + ulong idx = 0; zval *opts, *old_opts, **opt; getObject(http_request_object, obj); @@ -1716,6 +1728,29 @@ PHP_METHOD(HttpRequest, addPostFile) } /* }}} */ +/* {{{ 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. @@ -1753,6 +1788,59 @@ PHP_METHOD(HttpRequest, unsetPostFiles) } /* }}} */ +/* {{{ 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. @@ -1981,12 +2069,14 @@ PHP_METHOD(HttpRequest, getResponseMessage) getObject(http_request_object, obj); message = GET_PROP(obj, responseMessage); - Z_TYPE_P(return_value) = IS_OBJECT; - return_value->is_ref = 1; - return_value->value.obj = message->value.obj; - zval_add_ref(&return_value); + if (Z_TYPE_P(message) == IS_OBJECT) { + RETVAL_OBJECT(message); + } else { + RETURN_NULL(); + } } } +/* }}} */ /* {{{ proto bool HttpRequest::send() * @@ -2025,130 +2115,218 @@ PHP_METHOD(HttpRequest, getResponseMessage) 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([HttpRequest request[, ...]]) + * + * Instantiate a new HttpRequestPool object. An HttpRequestPool is + * able to send several HttpRequests in parallel. + * + * Example: + *
+ * attach($req[$url]);
+ *     }
+ *     $pool->send();
+ *     foreach ($urls as $url) {
+ *         printf("%s (%s) is %s\n",
+ *             $url, $req[$url]->getResponseInfo('effective_url'),
+ *             $r->getResponseCode() == 200 ? 'alive' : 'not alive'
+ *         );
+ *     }
+ * ?>
+ * 
+ */ +PHP_METHOD(HttpRequestPool, __construct) +{ + int argc = ZEND_NUM_ARGS(); + zval ***argv = safe_emalloc(argc, sizeof(zval *), 0); + getObject(http_requestpool_object, obj); + + if (SUCCESS == zend_get_parameters_array_ex(argc, argv)) { + int i; - 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); + for (i = 0; i < argc; ++i) { + if (Z_TYPE_PP(argv[i]) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(argv[i]), http_request_object_ce TSRMLS_CC)) { + http_request_pool_attach(&obj->pool, *(argv[i])); } } - break; - - default: - { - http_request_body body; - zval *post = GET_PROP(obj, postData); + } + efree(argv); +} +/* }}} */ - body.type = HTTP_REQUEST_BODY_CSTRING; - body.data = Z_STRVAL_P(post); - body.size = Z_STRLEN_P(post); +/* {{{ proto void HttpRequestPool::__destruct() + * + * Clean up HttpRequestPool object. + */ +PHP_METHOD(HttpRequestPool, __destruct) +{ + getObject(http_requestpool_object, obj); - status = http_request_ex(obj->ch, Z_LVAL_P(meth), request_uri, &body, Z_ARRVAL_P(opts), Z_ARRVAL_P(info), &obj->response); - } - break; - } + NO_ARGS; - efree(request_uri); + http_request_pool_detach_all(&obj->pool); +} +/* }}} */ - /* final data handling */ - if (status == SUCCESS) { - http_message *msg; +/* {{{ proto void HttpRequestPool::reset() + * + * Detach all attached HttpRequest objects. + */ +PHP_METHOD(HttpRequestPool, reset) +{ + 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); + http_request_pool_detach_all(&obj->pool); +} - MAKE_STD_ZVAL(headers) - array_init(headers); +/* {{{ 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); - 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); + 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); +} +/* }}} */ - add_assoc_zval(resp, "headers", headers); - add_assoc_stringl(resp, "body", body, body_len, 0); +/* {{{ 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); - 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; - } + 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); +} +/* }}} */ + +/* {{{ proto bool HttpRequestPool::send() + * + * Send all attached HttpRequest objects in parallel. + */ +PHP_METHOD(HttpRequestPool, send) +{ + STATUS status; + getObject(http_requestpool_object, obj); + NO_ARGS; + + SET_EH_THROW_HTTP(); + status = http_request_pool_send(&obj->pool); SET_EH_NORMAL(); + RETURN_SUCCESS(status); } /* }}} */ + +/* {{{ proto protected bool HttpRequestPool::socketSend() + * + * Usage: + *
+ * socketSend()) {
+ *         do_something_else();
+ *         if (!$pool->socketSelect()) {
+ *             die('Socket error');
+ *         }
+ *     }
+ *     $pool->socketRead();
+ * ?>
+ * 
+ */ +PHP_METHOD(HttpRequestPool, socketSend) +{ + getObject(http_requestpool_object, obj); + + NO_ARGS; + + RETURN_BOOL(0 < http_request_pool_perform(&obj->pool)); +} +/* }}} */ + +/* {{{ proto protected bool HttpRequestPool::socketSelect() + * + * See HttpRequestPool::socketSend(). + */ +PHP_METHOD(HttpRequestPool, socketSelect) +{ + getObject(http_requestpool_object, obj); + + NO_ARGS; + + RETURN_SUCCESS(http_request_pool_select(&obj->pool)); +} +/* }}} */ + +/* {{{ proto protected void HttpRequestPool::socketRead() + * + * See HttpRequestPool::socketSend(). + */ +PHP_METHOD(HttpRequestPool, socketRead) +{ + getObject(http_requestpool_object, obj); + + NO_ARGS; + + zend_llist_apply(&obj->pool.handles, (llist_apply_func_t) http_request_pool_responsehandler TSRMLS_CC); +} +/* }}} */ + +/* }}} */ + /* }}} */ #endif /* HTTP_HAVE_CURL */ @@ -2162,3 +2340,4 @@ PHP_METHOD(HttpRequest, send) * vim600: noet sw=4 ts=4 fdm=marker * vim<600: noet sw=4 ts=4 */ +