From 93a48c0a6710c7aa678ce0b48e6c1a5d2bf544ee Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Sun, 5 Feb 2006 21:18:14 +0000 Subject: [PATCH] - implement accessors to messages response status text - implement FR #6698 etag support (like 'lastmodified') - add test --- http_message_object.c | 52 ++++++++++++++++++++++++++++++++++ http_request_api.c | 57 ++++++++++++++++++++++++-------------- http_request_object.c | 20 +++++++++++++ php_http_message_object.h | 2 ++ php_http_request_object.h | 1 + tests/HttpMessage_001.phpt | 11 +++++--- tests/request_etag.phpt | 21 ++++++++++++++ 7 files changed, 139 insertions(+), 25 deletions(-) create mode 100644 tests/request_etag.phpt diff --git a/http_message_object.c b/http_message_object.c index 00a8007..b02dead 100644 --- a/http_message_object.c +++ b/http_message_object.c @@ -76,6 +76,11 @@ HTTP_BEGIN_ARGS(setResponseCode, 0, 1) HTTP_ARG_VAL(response_code, 0) HTTP_END_ARGS; +HTTP_EMPTY_ARGS(getResponseStatus, 0); +HTTP_BEGIN_ARGS(setResponseStatus, 0, 1) + HTTP_ARG_VAL(response_status, 0) +HTTP_END_ARGS; + HTTP_EMPTY_ARGS(getRequestMethod, 0); HTTP_BEGIN_ARGS(setRequestMethod, 0, 1) HTTP_ARG_VAL(request_method, 0) @@ -138,6 +143,8 @@ zend_function_entry http_message_object_fe[] = { HTTP_MESSAGE_ME(setType, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(getResponseCode, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(setResponseCode, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME(getResponseStatus, ZEND_ACC_PUBLIC) + HTTP_MESSAGE_ME(setResponseStatus, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(getRequestMethod, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(setRequestMethod, ZEND_ACC_PUBLIC) HTTP_MESSAGE_ME(getRequestUrl, ZEND_ACC_PUBLIC) @@ -253,6 +260,7 @@ static inline void _http_message_object_declare_default_properties(TSRMLS_D) DCL_PROP(PROTECTED, string, body, ""); DCL_PROP(PROTECTED, string, requestMethod, ""); DCL_PROP(PROTECTED, string, requestUrl, ""); + DCL_PROP(PROTECTED, string, responseStatus, ""); DCL_PROP(PROTECTED, long, responseCode, 0); DCL_PROP_N(PROTECTED, httpVersion); DCL_PROP_N(PROTECTED, headers); @@ -832,6 +840,50 @@ PHP_METHOD(HttpMessage, setResponseCode) } /* }}} */ +/* {{{ proto string HttpMessage::getResponseStatus() + * + * Get the Response Status of the message (i.e. the string following the response code). + * + * Returns the HTTP response status string if the message is of type + * HttpMessage::TYPE_RESPONSE, else FALSE. + */ +PHP_METHOD(HttpMessage, getResponseStatus) +{ + NO_ARGS; + + IF_RETVAL_USED { + getObject(http_message_object, obj); + HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); + RETURN_STRING(obj->message->http.info.response.status, 1); + } +} +/* }}} */ + +/* {{{ proto bool HttpMessage::setResponseStatus(string status) + * + * Set the Response Status of the HTTP message (i.e. the string following the response code). + * + * Expects a string parameter containing the response status text. + * + * Returns TRUE on success or FALSE if the message is not of type + * HttpMessage::TYPE_RESPONSE. + */ +PHP_METHOD(HttpMessage, setResponseStatus) +{ + char *status; + int status_len; + getObject(http_message_object, obj); + + HTTP_CHECK_MESSAGE_TYPE_RESPONSE(obj->message, RETURN_FALSE); + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &status, &status_len)) { + RETURN_FALSE; + } + STR_SET(obj->message->http.info.response.status, estrdup(status)); + RETURN_TRUE; +} +/* }}} */ + /* {{{ proto string HttpMessage::getRequestMethod() * * Get the Request Method of the Message. diff --git a/http_request_api.c b/http_request_api.c index 0432582..c80b80b 100644 --- a/http_request_api.c +++ b/http_request_api.c @@ -569,6 +569,12 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti } } + /* resume */ + if ((zoption = http_request_option(request, options, "resume", IS_LONG)) && (Z_LVAL_P(zoption) != 0)) { + range_req = 1; + HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption)); + } + /* additional headers, array('name' => 'value') */ if (request->_cache.headers) { curl_slist_free_all(request->_cache.headers); @@ -587,7 +593,10 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti ZVAL_ADDREF(*header_val); convert_to_string_ex(header_val); - snprintf(header, 1023, "%s: %s", header_key, Z_STRVAL_PP(header_val)); + if (!strcasecmp(header_key, "range")) { + range_req = 1; + } + snprintf(header, lenof(header), "%s: %s", header_key, Z_STRVAL_PP(header_val)); request->_cache.headers = curl_slist_append(request->_cache.headers, header); zval_ptr_dtor(header_val); } @@ -597,11 +606,37 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti } } } + /* etag */ + if ((zoption = http_request_option(request, options, "etag", IS_STRING)) && Z_STRLEN_P(zoption)) { + char match_header[1024] = {0}, *quoted_etag = NULL; + + if ((Z_STRVAL_P(zoption)[0] != '"') || (Z_STRVAL_P(zoption)[Z_STRLEN_P(zoption)-1] != '"')) { + spprintf("ed_etag, 0, "\"%s\"", Z_STRVAL_P(zoption)); + } + snprintf(match_header, lenof(match_header), "%s: %s", range_req?"If-Match":"If-None-Match", quoted_etag?quoted_etag:Z_STRVAL_P(zoption)); + request->_cache.headers = curl_slist_append(request->_cache.headers, match_header); + STR_FREE(quoted_etag); + } + /* compression */ if ((zoption = http_request_option(request, options, "compress", IS_BOOL)) && Z_LVAL_P(zoption)) { request->_cache.headers = curl_slist_append(request->_cache.headers, "Accept-Encoding: gzip;q=1.0,deflate;q=0.5"); } HTTP_CURL_OPT(CURLOPT_HTTPHEADER, request->_cache.headers); + /* lastmodified */ + if ((zoption = http_request_option(request, options, "lastmodified", IS_LONG))) { + if (Z_LVAL_P(zoption)) { + if (Z_LVAL_P(zoption) > 0) { + HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption)); + } else { + HTTP_CURL_OPT(CURLOPT_TIMEVALUE, HTTP_GET_REQUEST_TIME() + Z_LVAL_P(zoption)); + } + HTTP_CURL_OPT(CURLOPT_TIMECONDITION, range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE); + } else { + HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE); + } + } + /* cookies, array('name' => 'value') */ if ((zoption = http_request_option(request, options, "cookies", IS_ARRAY))) { phpstr_dtor(&request->_cache.cookies); @@ -638,12 +673,6 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti HTTP_CURL_OPT(CURLOPT_COOKIEJAR, Z_STRVAL_P(zoption)); } - /* resume */ - if ((zoption = http_request_option(request, options, "resume", IS_LONG)) && (Z_LVAL_P(zoption) != 0)) { - range_req = 1; - HTTP_CURL_OPT(CURLOPT_RESUME_FROM, Z_LVAL_P(zoption)); - } - /* maxfilesize */ if ((zoption = http_request_option(request, options, "maxfilesize", IS_LONG))) { HTTP_CURL_OPT(CURLOPT_MAXFILESIZE, Z_LVAL_P(zoption)); @@ -654,20 +683,6 @@ PHP_HTTP_API STATUS _http_request_prepare(http_request *request, HashTable *opti HTTP_CURL_OPT(CURLOPT_HTTP_VERSION, Z_LVAL_P(zoption)); } - /* lastmodified */ - if ((zoption = http_request_option(request, options, "lastmodified", IS_LONG))) { - if (Z_LVAL_P(zoption)) { - if (Z_LVAL_P(zoption) > 0) { - HTTP_CURL_OPT(CURLOPT_TIMEVALUE, Z_LVAL_P(zoption)); - } else { - HTTP_CURL_OPT(CURLOPT_TIMEVALUE, HTTP_GET_REQUEST_TIME() + Z_LVAL_P(zoption)); - } - HTTP_CURL_OPT(CURLOPT_TIMECONDITION, range_req ? CURL_TIMECOND_IFUNMODSINCE : CURL_TIMECOND_IFMODSINCE); - } else { - HTTP_CURL_OPT(CURLOPT_TIMECONDITION, CURL_TIMECOND_NONE); - } - } - /* timeout, defaults to 0 */ if ((zoption = http_request_option(request, options, "timeout", IS_LONG))) { HTTP_CURL_OPT(CURLOPT_TIMEOUT, Z_LVAL_P(zoption)); diff --git a/http_request_object.c b/http_request_object.c index 6f5b034..cd77474 100644 --- a/http_request_object.c +++ b/http_request_object.c @@ -140,6 +140,7 @@ HTTP_END_ARGS; HTTP_EMPTY_ARGS(getResponseBody, 0); HTTP_EMPTY_ARGS(getResponseCode, 0); +HTTP_EMPTY_ARGS(getResponseStatus, 0); HTTP_BEGIN_ARGS(getResponseInfo, 0, 0) HTTP_ARG_VAL(name, 0) HTTP_END_ARGS; @@ -264,6 +265,7 @@ zend_function_entry http_request_object_fe[] = { HTTP_REQUEST_ME(getResponseHeader, ZEND_ACC_PUBLIC) HTTP_REQUEST_ME(getResponseCookie, ZEND_ACC_PUBLIC) HTTP_REQUEST_ME(getResponseCode, ZEND_ACC_PUBLIC) + HTTP_REQUEST_ME(getResponseStatus, ZEND_ACC_PUBLIC) HTTP_REQUEST_ME(getResponseBody, ZEND_ACC_PUBLIC) HTTP_REQUEST_ME(getResponseInfo, ZEND_ACC_PUBLIC) HTTP_REQUEST_ME(getResponseMessage, ZEND_ACC_PUBLIC) @@ -357,6 +359,7 @@ static inline void _http_request_object_declare_default_properties(TSRMLS_D) DCL_PROP_N(PRIVATE, responseData); DCL_PROP_N(PRIVATE, responseMessage); DCL_PROP(PRIVATE, long, responseCode, 0); + DCL_PROP(PRIVATE, string, responseStatus, ""); DCL_PROP(PRIVATE, long, method, HTTP_GET); DCL_PROP(PRIVATE, string, url, ""); DCL_PROP(PRIVATE, string, contentType, ""); @@ -590,6 +593,7 @@ STATUS _http_request_object_responsehandler(http_request_object *obj, zval *this } UPD_PROP(long, responseCode, msg->http.info.response.code); + UPD_PROP(string, responseStatus, msg->http.info.response.status); MAKE_STD_ZVAL(resp); array_init(resp); @@ -1641,6 +1645,22 @@ PHP_METHOD(HttpRequest, getResponseCode) } /* }}} */ +/* {{{ proto string HttpRequest::getResponseStatus() + * + * Get the response status (i.e. the string after the response code) after the message has been sent. + * + * Returns a string containing the response status text. + */ +PHP_METHOD(HttpRequest, getResponseStatus) +{ + NO_ARGS; + + IF_RETVAL_USED { + RETURN_PROP(responseStatus); + } +} +/* }}} */ + /* {{{ proto mixed HttpRequest::getResponseInfo([string name]) * * Get response info after the request has been sent. diff --git a/php_http_message_object.h b/php_http_message_object.h index 97f8214..62760f7 100644 --- a/php_http_message_object.h +++ b/php_http_message_object.h @@ -80,6 +80,8 @@ PHP_METHOD(HttpMessage, getType); PHP_METHOD(HttpMessage, setType); PHP_METHOD(HttpMessage, getResponseCode); PHP_METHOD(HttpMessage, setResponseCode); +PHP_METHOD(HttpMessage, getResponseStatus); +PHP_METHOD(HttpMessage, setResponseStatus); PHP_METHOD(HttpMessage, getRequestMethod); PHP_METHOD(HttpMessage, setRequestMethod); PHP_METHOD(HttpMessage, getRequestUrl); diff --git a/php_http_request_object.h b/php_http_request_object.h index bbb4e96..7713e28 100644 --- a/php_http_request_object.h +++ b/php_http_request_object.h @@ -82,6 +82,7 @@ PHP_METHOD(HttpRequest, getResponseData); PHP_METHOD(HttpRequest, getResponseHeader); PHP_METHOD(HttpRequest, getResponseCookie); PHP_METHOD(HttpRequest, getResponseCode); +PHP_METHOD(HttpRequest, getResponseStatus); PHP_METHOD(HttpRequest, getResponseBody); PHP_METHOD(HttpRequest, getResponseInfo); PHP_METHOD(HttpRequest, getResponseMessage); diff --git a/tests/HttpMessage_001.phpt b/tests/HttpMessage_001.phpt index 25adb8f..c2fe79a 100644 --- a/tests/HttpMessage_001.phpt +++ b/tests/HttpMessage_001.phpt @@ -13,7 +13,7 @@ $m = new HttpMessage( "Location: /anywhere\r\n". "HTTP/1.1 302\r\n". "Location: /somewhere\r\n". - "HTTP/1.1 206\r\n". + "HTTP/1.1 206 Partial content\r\n". "Content-Range: bytes=2-3\r\n". "Transfer-Encoding: chunked\r\n". "\r\n". @@ -22,6 +22,8 @@ $m = new HttpMessage( "00" ); +var_dump($m->getResponseStatus()); + $x = $m->getParentMessage(); $x = $m->getParentMessage(); $x = $m->getParentMessage(); @@ -36,19 +38,20 @@ echo "Done\n"; ?> --EXPECTF-- %sTEST +string(15) "Partial content" string(1) "X" -string(174) "HTTP/1.1 301 +string(190) "HTTP/1.1 301 Location: /anywhere HTTP/1.1 302 Location: /somewhere -HTTP/1.1 206 +HTTP/1.1 206 Partial content Content-Range: bytes=2-3 X-Original-Transfer-Encoding: chunked Content-Length: 1 X " -string(103) "HTTP/1.1 206 +string(119) "HTTP/1.1 206 Partial content Content-Range: bytes=2-3 X-Original-Transfer-Encoding: chunked Content-Length: 1 diff --git a/tests/request_etag.phpt b/tests/request_etag.phpt new file mode 100644 index 0000000..69b26d2 --- /dev/null +++ b/tests/request_etag.phpt @@ -0,0 +1,21 @@ +--TEST-- +request etag +--SKIPIF-- + +--FILE-- + '"26ad3a-5-95eb19c0"'))); +echo "Done\n"; +?> +--EXPECTF-- +%sTEST +string(%d) "HTTP/1.1 304 Not Modified +Date: %s +Server: %s +ETag: "26ad3a-5-95eb19c0" +" +Done \ No newline at end of file -- 2.30.2