From 02b671786e119a62ebe1a8183d682a39b4958a7b Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 09:05:46 +0000 Subject: [PATCH 01/16] filter tests & fixes --- php_http_filter.c | 42 ++++++++++++++++++++-------------------- tests/filterchunked.phpt | 29 +++++++++++++++++++++++++++ tests/filterzlib.phpt | 29 +++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 21 deletions(-) create mode 100644 tests/filterchunked.phpt create mode 100644 tests/filterzlib.phpt diff --git a/php_http_filter.c b/php_http_filter.c index 121966b..2c53358 100644 --- a/php_http_filter.c +++ b/php_http_filter.c @@ -363,7 +363,28 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int { zval **tmp = ¶ms; 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 (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) { + break; + } + /* no break */ + default: + { + zval *num = php_http_ztyp(IS_LONG, *tmp); + + flags |= (Z_LVAL_P(num) & 0x0fffffff); + zval_ptr_dtor(&num); + + } + break; + } + } + if (!strcasecmp(name, "http.chunked_decode")) { PHP_HTTP_FILTER_BUFFER(chunked_decode) *b = NULL; @@ -380,7 +401,6 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int } else if (!strcasecmp(name, "http.inflate")) { - int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0; PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL; if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_inflate_ops(), flags TSRMLS_CC))) { @@ -391,28 +411,8 @@ static php_stream_filter *http_filter_create(const char *name, zval *params, int } else if (!strcasecmp(name, "http.deflate")) { - int flags = p ? PHP_HTTP_ENCODING_STREAM_PERSISTENT : 0; PHP_HTTP_FILTER_BUFFER(zlib) *b = NULL; - if (params) { - switch (Z_TYPE_P(params)) { - case IS_ARRAY: - case IS_OBJECT: - if (SUCCESS != zend_hash_find(HASH_OF(params), "flags", sizeof("flags"), (void *) &tmp)) { - break; - } - /* no break */ - default: - { - zval *num = php_http_ztyp(IS_LONG, *tmp); - - flags |= (Z_LVAL_P(num) & 0x0fffffff); - zval_ptr_dtor(&num); - - } - break; - } - } if ((b = php_http_encoding_stream_init(NULL, php_http_encoding_stream_get_deflate_ops(), flags TSRMLS_CC))) { if (!(f = php_stream_filter_alloc(&PHP_HTTP_FILTER_OP(deflate), b, p))) { php_http_encoding_stream_free(&b); diff --git a/tests/filterchunked.phpt b/tests/filterchunked.phpt new file mode 100644 index 0000000..f2d2850 --- /dev/null +++ b/tests/filterchunked.phpt @@ -0,0 +1,29 @@ +--TEST-- +chunked filter +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE diff --git a/tests/filterzlib.phpt b/tests/filterzlib.phpt new file mode 100644 index 0000000..bbfac86 --- /dev/null +++ b/tests/filterzlib.phpt @@ -0,0 +1,29 @@ +--TEST-- +zlib filter +--SKIPIF-- + +--FILE-- + +DONE +--EXPECT-- +DONE -- 2.30.2 From 59ffe749e2571c7e4bf0cce12997f95f350bd58c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 09:06:37 +0000 Subject: [PATCH 02/16] fix bug #60839 php_http_serf.h missing; prepare dev4 release --- package.xml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.xml b/package.xml index bc55518..0ea30cc 100644 --- a/package.xml +++ b/package.xml @@ -19,9 +19,9 @@ Extended HTTP support. Again. mike@php.net yes - 2012-01-16 + 2012-01-23 - 2.0.0dev3 + 2.0.0dev4 2.0.0 @@ -110,6 +110,7 @@ List of changes (TBD): + -- 2.30.2 From 7e993d04d015e468c9b4e8ae48db243f1d53aa2c Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 09:26:27 +0000 Subject: [PATCH 03/16] make place for real release notes; keep a major changes section in the description for now --- package.xml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/package.xml b/package.xml index 0ea30cc..222c516 100644 --- a/package.xml +++ b/package.xml @@ -11,7 +11,15 @@ pecl.php.net Extended HTTP Support errorHandling. +* The request ecosystem has been modularized to support different libraries, though for the moment only libcurl is supported; + Nevertheless, you have to use the http\Request\Factory to create your request/pool/datashare objects. ]]> Michael Wallner @@ -21,7 +29,7 @@ Extended HTTP support. Again. 2012-01-23 - 2.0.0dev4 + 2.0.0dev 2.0.0 @@ -30,17 +38,6 @@ Extended HTTP support. Again. BSD, revised errorHandling, but only for errors generated by the extension itself -* You have to use the http\Request\Factory to create your requests/pools/datashares ]]> -- 2.30.2 From 120c2279bdf9db8486a60b0e85c0e31f6ff4e8fc Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 14:13:33 +0000 Subject: [PATCH 04/16] initialize with NULL --- php_http_env.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php_http_env.c b/php_http_env.c index eb7a630..f7df9d0 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -694,7 +694,7 @@ PHP_METHOD(HttpEnv, setResponseHeader) { char *header_name_str; int header_name_len; - zval *header_value; + zval *header_value = NULL; long code = 0; zend_bool replace_header = 1; -- 2.30.2 From a3ac311bb52e1947e743739c9d165b7aa01583b8 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 14:14:10 +0000 Subject: [PATCH 05/16] encoding tests & fixes --- php_http_encoding.c | 94 ++++++++++++++++------ phpunit/EncodingTest.php | 165 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 22 deletions(-) create mode 100644 phpunit/EncodingTest.php diff --git a/php_http_encoding.c b/php_http_encoding.c index b34594c..ce47fcd 100644 --- a/php_http_encoding.c +++ b/php_http_encoding.c @@ -35,7 +35,7 @@ PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t e const char *e_ptr = encoded; *decoded_len = 0; - *decoded = ecalloc(1, encoded_len); + *decoded = ecalloc(1, encoded_len + 1); while ((encoded + encoded_len - e_ptr) > 0) { ulong chunk_len = 0, rest; @@ -53,6 +53,7 @@ PHP_HTTP_API const char *php_http_encoding_dechunk(const char *encoded, size_t e php_http_error(HE_NOTICE, PHP_HTTP_E_ENCODING, "Data does not seem to be chunked encoded"); memcpy(*decoded, encoded, encoded_len); *decoded_len = encoded_len; + decoded[*decoded_len] = '\0'; return encoded + encoded_len; } else { efree(*decoded); @@ -265,11 +266,31 @@ PHP_HTTP_API php_http_encoding_stream_t *php_http_encoding_stream_copy(php_http_ { TSRMLS_FETCH_FROM_CTX(from->ts); - if (!from->ops->copy) { - return NULL; + 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; + TSRMLS_SET_CTX(to->ts); + + if ((ns = to->ops->copy(from, to))) { + return ns; + } else { + return to; + } + + if (freeme) { + pefree(to, (to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT)); + } } - return from->ops->copy(from, php_http_encoding_stream_init(to, from->ops, from->flags TSRMLS_CC)); + return NULL; } PHP_HTTP_API STATUS php_http_encoding_stream_reset(php_http_encoding_stream_t **s) @@ -406,33 +427,58 @@ static php_http_encoding_stream_t *dechunk_init(php_http_encoding_stream_t *s) static php_http_encoding_stream_t *deflate_copy(php_http_encoding_stream_t *from, php_http_encoding_stream_t *to) { - z_streamp from_ctx = from->ctx, to_ctx = to->ctx; - - deflateCopy(to_ctx, from_ctx); - php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque)); + int status, p = to->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); - return to; + 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_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque)); + to->ctx = to_ctx; + return to; + } + deflateEnd(to_ctx); + status = Z_MEM_ERROR; + } + php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "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) { - z_streamp from_ctx = from->ctx, to_ctx = to->ctx; - - inflateCopy(to_ctx, from_ctx); - php_http_buffer_append(to_ctx->opaque, PHP_HTTP_BUFFER_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque)); + int status, p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + z_streamp from_ctx = from->ctx, to_ctx = pecalloc(1, sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); - return to; + 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_VAL(from_ctx->opaque), PHP_HTTP_BUFFER_LEN(from_ctx->opaque)); + to->ctx = to_ctx; + return to; + } + inflateEnd(to_ctx); + status = Z_MEM_ERROR; + } + php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "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) { - struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = to->ctx; - - to_ctx->hexlen = from_ctx->hexlen; - to_ctx->zeroed = from_ctx->zeroed; - php_http_buffer_append(&to_ctx->buffer, PHP_HTTP_BUFFER_VAL(&from_ctx->buffer), PHP_HTTP_BUFFER_LEN(&from_ctx->buffer)); + int p = from->flags & PHP_HTTP_ENCODING_STREAM_PERSISTENT; + struct dechunk_ctx *from_ctx = from->ctx, *to_ctx = pemalloc(sizeof(*to_ctx), p); + TSRMLS_FETCH_FROM_CTX(from->ts); - return to; + 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, PHP_HTTP_BUFFER_VAL(&from_ctx->buffer), PHP_HTTP_BUFFER_LEN(&from_ctx->buffer)); + to->ctx = to_ctx; + return to; + } + pefree(to_ctx, p); + php_http_error(HE_WARNING, PHP_HTTP_E_ENCODING, "Failed to copy inflate encoding stream: out of memory"); + return NULL; } static STATUS deflate_update(php_http_encoding_stream_t *s, const char *data, size_t data_len, char **encoded, size_t *encoded_len) @@ -1041,7 +1087,11 @@ PHP_METHOD(HttpEncodingStream, finish) if (SUCCESS == php_http_encoding_stream_finish(obj->stream, &encoded_str, &encoded_len)) { if (SUCCESS == php_http_encoding_stream_reset(&obj->stream)) { - RETURN_STRINGL(encoded_str, encoded_len, 0); + if (encoded_str) { + RETURN_STRINGL(encoded_str, encoded_len, 0); + } else { + RETURN_EMPTY_STRING(); + } } else { STR_FREE(encoded_str); } @@ -1141,7 +1191,7 @@ PHP_METHOD(HttpDechunkStream, decode) { char *str; int len; - zval *zlen; + zval *zlen = NULL; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z!", &str, &len, &zlen)) { const char *end_ptr; diff --git a/phpunit/EncodingTest.php b/phpunit/EncodingTest.php new file mode 100644 index 0000000..5fb2df3 --- /dev/null +++ b/phpunit/EncodingTest.php @@ -0,0 +1,165 @@ +assertEquals(implode("", $file), http\Encoding\Stream\Dechunk::decode($cenc)); + } + + function testChunkNoteEncoded() { + $s = "this is apparently not encodded\n"; + $this->assertEquals($s, @http\Encoding\Stream\Dechunk::decode($s)); + } + + function testChunkNotEncodedNotice() { + $this->setExpectedException("PHPUnit_Framework_Error_Notice", + "Data does not seem to be chunked encoded"); + $s = "this is apparently not encodded\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkNotEncodedFail() { + $s = "3\nis \nbetter than\n1\n"; + $this->assertNotEquals($s, @http\Encoding\Stream\Dechunk::decode($s)); + } + + function testChunkNotEncodedWarning1() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected LF at pos 8 of 20 but got 0x74"); + $s = "3\nis \nbetter than\n1\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkNotEncodedWarning2() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected CRLF at pos 10 of 24 but got 0x74 0x74"); + $s = "3\r\nis \r\nbetter than\r\n1\r\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkNotEncodedWarning3() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Expected chunk size at pos 6 of 27 but got trash"); + $s = "3\nis \nreally better than\n1\n"; + http\Encoding\Stream\Dechunk::decode($s); + } + + function testChunkFlush() { + $dech = new http\Encoding\Stream\Dechunk(http\Encoding\Stream::FLUSH_FULL); + $file = file(__FILE__); + $data = ""; + foreach ($file as $i => $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->update($line); + $data .= $dech->update("\r\n"); + } + $this->assertFalse($dech->done()); + } + $data .= $dech->update("0\r\n"); + $this->assertTrue($dech->done()); + $data .= $dech->finish(); + $this->assertEquals(implode("", $file), $data); + } + + function testZlibStatic() { + $file = file_get_contents(__FILE__); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_GZIP + ) + ) + ); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_ZLIB + ) + ) + ); + $this->assertEquals($file, + http\Encoding\Stream\Inflate::decode( + http\Encoding\Stream\Deflate::encode( + $file, http\Encoding\Stream\Deflate::TYPE_RAW + ) + ) + ); + } + + function testZlibAutoFlush() { + $defl = new http\Encoding\Stream\Deflate(http\Encoding\Stream::FLUSH_FULL); + $infl = new http\Encoding\Stream\Inflate; + + for ($f = fopen(__FILE__, "rb"); !feof($f); $data = fread($f, 0x100)) { + $infl = clone $infl; + $defl = clone $defl; + if (isset($data)) { + $this->assertEquals($data, $infl->update($defl->update($data))); + } + } + + echo $infl->update($defl->finish()); + echo $infl->finish(); + } + + function testZlibWithoutFlush() { + $defl = new http\Encoding\Stream\Deflate; + $infl = new http\Encoding\Stream\Inflate; + $file = file(__FILE__); + $data = ""; + foreach ($file as $line) { + $infl = clone $infl; + $defl = clone $defl; + if (strlen($temp = $defl->update($line))) { + foreach(str_split($temp) as $byte) { + $data .= $infl->update($byte); + } + } + } + if (strlen($temp = $defl->finish())) { + $data .= $infl->update($temp); + } + $data .= $infl->finish(); + $this->assertEquals(implode("", $file), $data); + } + + function testZlibWithExplicitFlush() { + $defl = new http\Encoding\Stream\Deflate; + $infl = new http\Encoding\Stream\Inflate; + $file = file(__FILE__); + $data = ""; + foreach ($file as $line) { + if (strlen($temp = $defl->update($line))) { + $data .= $infl->update($temp); + } + if (strlen($temp = $defl->flush())) { + $data .= $infl->update($temp); + } + $this->assertTrue($defl->done()); + } + if (strlen($temp = $defl->finish())) { + $data .= $infl->update($temp); + } + $this->assertTrue($defl->done()); + $data .= $infl->finish(); + $this->assertTrue($infl->done()); + $this->assertEquals(implode("", $file), $data); + } + + function testInflateError() { + $this->setExpectedException("PHPUnit_Framework_Error_Warning", + "Could not inflate data: data error"); + http\Encoding\Stream\Inflate::decode("if this goes through, something's pretty wrong"); + } +} -- 2.30.2 From a5e1d0cdf87105d3577ca2db9cb2c5c380062c10 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 15:18:28 +0000 Subject: [PATCH 06/16] negotiation test & fixes --- php_http_env.c | 22 ++++++++ php_http_env.h | 1 + php_http_negotiate.c | 5 ++ tests/negotiate001.phpt | 111 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 tests/negotiate001.phpt diff --git a/php_http_env.c b/php_http_env.c index f7df9d0..a0232d2 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -575,6 +575,11 @@ PHP_HTTP_BEGIN_ARGS(negotiateCharset, 1) PHP_HTTP_ARG_VAL(result_array, 1) PHP_HTTP_END_ARGS; +PHP_HTTP_BEGIN_ARGS(negotiateEncoding, 1) + PHP_HTTP_ARG_VAL(supported, 0) + PHP_HTTP_ARG_VAL(result_array, 1) +PHP_HTTP_END_ARGS; + PHP_HTTP_BEGIN_ARGS(negotiate, 2) PHP_HTTP_ARG_VAL(value, 0) PHP_HTTP_ARG_VAL(supported, 0) @@ -602,6 +607,7 @@ zend_function_entry php_http_env_method_entry[] = { PHP_HTTP_ENV_ME(negotiateLanguage) PHP_HTTP_ENV_ME(negotiateContentType) + PHP_HTTP_ENV_ME(negotiateEncoding) PHP_HTTP_ENV_ME(negotiateCharset) PHP_HTTP_ENV_ME(negotiate) @@ -747,6 +753,22 @@ PHP_METHOD(HttpEnv, negotiateCharset) } } +PHP_METHOD(HttpEnv, negotiateEncoding) +{ + HashTable *supported; + zval *rs_array = NULL; + + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "H|z", &supported, &rs_array)) { + if (rs_array) { + zval_dtor(rs_array); + array_init(rs_array); + } + PHP_HTTP_DO_NEGOTIATE(encoding, supported, rs_array); + } else { + RETURN_FALSE; + } +} + PHP_METHOD(HttpEnv, negotiateContentType) { HashTable *supported; diff --git a/php_http_env.h b/php_http_env.h index 62e22cd..64cc702 100644 --- a/php_http_env.h +++ b/php_http_env.h @@ -81,6 +81,7 @@ PHP_METHOD(HttpEnv, setResponseHeader); PHP_METHOD(HttpEnv, setResponseCode); PHP_METHOD(HttpEnv, negotiateLanguage); PHP_METHOD(HttpEnv, negotiateCharset); +PHP_METHOD(HttpEnv, negotiateEncoding); PHP_METHOD(HttpEnv, negotiateContentType); PHP_METHOD(HttpEnv, negotiate); PHP_METHOD(HttpEnv, persistentHandlesStat); diff --git a/php_http_negotiate.c b/php_http_negotiate.c index aeb9521..69c7393 100644 --- a/php_http_negotiate.c +++ b/php_http_negotiate.c @@ -74,6 +74,11 @@ PHP_HTTP_API HashTable *php_http_negotiate(const char *value_str, size_t value_l q = Z_DVAL_P(tmp); zval_ptr_dtor(&tmp); + + if (!q) { + STR_FREE(key.str); + continue; + } } else { q = 1.0 - ++i / 100.0; } diff --git a/tests/negotiate001.phpt b/tests/negotiate001.phpt new file mode 100644 index 0000000..b71efe0 --- /dev/null +++ b/tests/negotiate001.phpt @@ -0,0 +1,111 @@ +--TEST-- +negotiate +--SKIPIF-- + +--ENV-- +HTTP_ACCEPT=text/html,text/plain,text/xml;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 + + +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.899 + [en] => 0.8 +) +de-DE: Array +( + [de-DE] => 0.99 + [de-AT] => 0.9 + [en] => 0.8 +) +en: Array +( + [en] => 0.8 +) +DONE -- 2.30.2 From 4407379af8d886b627c88572e9da69c38cdbda58 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 23 Jan 2012 16:36:58 +0000 Subject: [PATCH 07/16] etag test & fixes; set default etag mode for temp streams to crc32(b) --- php_http.c | 2 +- php_http_env_response.c | 9 ++--- php_http_etag.c | 65 +++++++++++++++++++++---------------- php_http_message_body.c | 8 +++-- phpunit/MessageBodyTest.php | 2 +- tests/etag001.phpt | 64 ++++++++++++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 36 deletions(-) create mode 100644 tests/etag001.phpt diff --git a/php_http.c b/php_http.c index 36f2caa..889cb09 100644 --- a/php_http.c +++ b/php_http.c @@ -118,7 +118,7 @@ zend_php_http_globals *php_http_globals(void) #endif #endif PHP_INI_BEGIN() - PHP_HTTP_INI_ENTRY("http.etag.mode", "md5", PHP_INI_ALL, OnUpdateString, env.etag_mode) + PHP_HTTP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode) PHP_HTTP_INI_ENTRY("http.request_datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.cookie) PHP_HTTP_INI_ENTRY("http.request_datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.dns) PHP_HTTP_INI_ENTRY("http.request_datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.ssl) diff --git a/php_http_env_response.c b/php_http_env_response.c index 2ddcb71..0d220d0 100644 --- a/php_http_env_response.c +++ b/php_http_env_response.c @@ -77,7 +77,7 @@ static zval *get_option(zval *options, const char *name_str, size_t name_len TSR 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 TSRMLS_DC) { - int ret, free_etag = 0; + int ret = 0, free_etag = 0; char *header, *etag; zval *zetag, *zbody = NULL; @@ -101,8 +101,7 @@ PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zva if (zetag && Z_STRLEN_P(zetag)) { etag = Z_STRVAL_P(zetag); - } else { - etag = php_http_message_body_etag(((php_http_message_body_object_t *) zend_object_store_get_object(zbody TSRMLS_CC))->body); + } else if ((etag = php_http_message_body_etag(((php_http_message_body_object_t *) zend_object_store_get_object(zbody TSRMLS_CC))->body))) { set_option(options, ZEND_STRL("etag"), IS_STRING, etag, strlen(etag) TSRMLS_CC); free_etag = 1; } @@ -115,7 +114,9 @@ PHP_HTTP_API php_http_cache_status_t php_http_env_is_response_cached_by_etag(zva zval_ptr_dtor(&zetag); } - ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD); + if (etag) { + ret = php_http_match(header, etag, PHP_HTTP_MATCH_WORD); + } if (free_etag) { efree(etag); diff --git a/php_http_etag.c b/php_http_etag.c index 891717d..3a69756 100644 --- a/php_http_etag.c +++ b/php_http_etag.c @@ -25,15 +25,7 @@ PHP_HTTP_API php_http_etag_t *php_http_etag_init(const char *mode TSRMLS_DC) void *ctx; php_http_etag_t *e; -#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 - if (mode && ((!strcasecmp(mode, "crc32")) || (!strcasecmp(mode, "crc32b")))) { + if (mode && (!strcasecmp(mode, "crc32b"))) { ctx = emalloc(sizeof(uint)); *((uint *) ctx) = ~0; } else if (mode && !strcasecmp(mode, "sha1")) { @@ -41,6 +33,14 @@ PHP_HTTP_API php_http_etag_t *php_http_etag_init(const char *mode TSRMLS_DC) } 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; } @@ -57,24 +57,32 @@ PHP_HTTP_API char *php_http_etag_finish(php_http_etag_t *e) unsigned char digest[128] = {0}; char *etag = NULL; -#ifdef PHP_HTTP_HAVE_HASH - const php_hash_ops *eho = NULL; + if (!strcasecmp(e->mode, "crc32b")) { + unsigned char buf[4]; - 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); - } else -#endif - if (((!strcasecmp(e->mode, "crc32")) || (!strcasecmp(e->mode, "crc32b")))) { *((uint *) e->ctx) = ~*((uint *) e->ctx); - etag = php_http_etag_digest((const unsigned char *) e->ctx, sizeof(uint)); + 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); } else if ((!strcasecmp(e->mode, "sha1"))) { PHP_SHA1Final(digest, e->ctx); etag = php_http_etag_digest(digest, 20); - } else { + } 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); @@ -84,14 +92,7 @@ PHP_HTTP_API char *php_http_etag_finish(php_http_etag_t *e) PHP_HTTP_API size_t php_http_etag_update(php_http_etag_t *e, const char *data_ptr, size_t data_len) { -#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); - } else -#endif - if (((!strcasecmp(e->mode, "crc32")) || (!strcasecmp(e->mode, "crc32b")))) { + if (!strcasecmp(e->mode, "crc32b")) { uint i, c = *((uint *) e->ctx); for (i = 0; i < data_len; ++i) { CRC32(c, data_ptr[i]); @@ -99,8 +100,16 @@ PHP_HTTP_API size_t php_http_etag_update(php_http_etag_t *e, const char *data_pt *((uint *) e->ctx) = c; } else if ((!strcasecmp(e->mode, "sha1"))) { PHP_SHA1Update(e->ctx, (const unsigned char *) data_ptr, data_len); - } else { + } 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; diff --git a/php_http_message_body.c b/php_http_message_body.c index c9cea55..7019de3 100644 --- a/php_http_message_body.c +++ b/php_http_message_body.c @@ -123,8 +123,12 @@ PHP_HTTP_API char *php_http_message_body_etag(php_http_message_body_t *body) } else { php_http_etag_t *etag = php_http_etag_init(PHP_HTTP_G->env.etag_mode TSRMLS_CC); - 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); + if (etag) { + 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); + } else { + return NULL; + } } } diff --git a/phpunit/MessageBodyTest.php b/phpunit/MessageBodyTest.php index bc07401..eda54b0 100644 --- a/phpunit/MessageBodyTest.php +++ b/phpunit/MessageBodyTest.php @@ -87,7 +87,7 @@ class MessageBodyTest extends PHPUnit_Framework_TestCase { ), $this->file->etag() ); - $this->assertEquals(md5(""), $this->temp->etag()); + $this->assertEquals(crc32(""), $this->temp->etag()); } function testToStream() { diff --git a/tests/etag001.phpt b/tests/etag001.phpt new file mode 100644 index 0000000..40b578d --- /dev/null +++ b/tests/etag001.phpt @@ -0,0 +1,64 @@ +--TEST-- +etags with hash +--SKIPIF-- + +--EXTENSIONS-- +hash +--FILE-- +append("Hello, my old fellow."); +foreach (hash_algos() as $algo) { + 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 + adler32: 4ff5075d + crc32: 757b06f7 + crc32b: e56655c5 + fnv132: ebd1fa1f + fnv164: 9790ce01eba3ae9f + 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 -- 2.30.2 From 762569513846ed320f863f4c2e51808015098610 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 24 Jan 2012 16:33:04 +0000 Subject: [PATCH 08/16] make sure we're not caught by uninitialized values --- php_http_env.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php_http_env.c b/php_http_env.c index a0232d2..a13e797 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -619,8 +619,8 @@ zend_function_entry php_http_env_method_entry[] = { PHP_METHOD(HttpEnv, getRequestHeader) { - char *header_name_str; - int header_name_len; + char *header_name_str = NULL; + int header_name_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!", &header_name_str, &header_name_len)) { if (header_name_str && header_name_len) { @@ -827,7 +827,7 @@ PHP_METHOD(HttpEnv, persistentHandlesClean) char *name_str = NULL, *ident_str = NULL; int name_len = 0, ident_len = 0; - if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ss", &name_str, &name_len, &ident_str, &ident_len)) { + if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!", &name_str, &name_len, &ident_str, &ident_len)) { php_http_persistent_handle_cleanup(name_str, name_len, ident_str, ident_len TSRMLS_CC); } } -- 2.30.2 From a4d37ccceca1eecd63e8b69c74f09ce679f39498 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 24 Jan 2012 16:33:49 +0000 Subject: [PATCH 09/16] return the actual zval instead of a string cast as header if join==0 --- php_http_message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/php_http_message.c b/php_http_message.c index 6436a1c..b3adb46 100644 --- a/php_http_message.c +++ b/php_http_message.c @@ -169,7 +169,8 @@ PHP_HTTP_API zval *php_http_message_header(php_http_message_t *msg, char *key_st ZVAL_STRINGL(header_str, PHP_HTTP_BUFFER_VAL(&str), PHP_HTTP_BUFFER_LEN(&str), 0); ret = header_str; } else { - ret = php_http_ztyp(IS_STRING, *header); + Z_ADDREF_PP(header); + ret = *header; } } -- 2.30.2 From 809cfb73a233ce951274a5951b921d5f5feb6676 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Tue, 24 Jan 2012 16:34:18 +0000 Subject: [PATCH 10/16] cookie test & fixes --- php_http_cookie.c | 216 +++++++++++++++++++++-------------------- php_http_params.c | 34 ++++--- phpunit/CookieTest.php | 179 ++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 122 deletions(-) create mode 100644 phpunit/CookieTest.php diff --git a/php_http_cookie.c b/php_http_cookie.c index a92bb5e..36fb1d4 100644 --- a/php_http_cookie.c +++ b/php_http_cookie.c @@ -23,7 +23,7 @@ PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_init(php_http_cookie_l list->path = NULL; list->domain = NULL; - list->expires = 0; + list->expires = -1; list->flags = 0; TSRMLS_SET_CTX(list->ts); @@ -114,6 +114,63 @@ PHP_HTTP_API void php_http_cookie_list_add_extra(php_http_cookie_list_t *list, c zend_symtable_update(&list->extras, name, name_len + 1, (void *) &cookie_value, sizeof(zval *), NULL); } +#define _KEY_IS(s) (key->len == sizeof(s) && !strncasecmp(key->str, (s), key->len)) +static void add_entry(php_http_cookie_list_t *list, char **allowed_extras, long flags, php_http_array_hashkey_t *key, zval *val) +{ + zval *arg = php_http_zsep(1, IS_STRING, val); + + if (!(flags & PHP_HTTP_COOKIE_PARSE_RAW)) { + Z_STRLEN_P(arg) = php_raw_url_decode(Z_STRVAL_P(arg), Z_STRLEN_P(arg)); + } + + if _KEY_IS("path") { + STR_SET(list->path, estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg))); + } else if _KEY_IS("domain") { + STR_SET(list->domain, estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg))); + } else if _KEY_IS("expires") { + char *date = estrndup(Z_STRVAL_P(arg), Z_STRLEN_P(arg)); + list->expires = php_parse_date(date, NULL); + efree(date); + } else if _KEY_IS("secure") { + list->flags |= PHP_HTTP_COOKIE_SECURE; + } else if _KEY_IS("httpOnly") { + list->flags |= PHP_HTTP_COOKIE_HTTPONLY; + } else { + char buf[0x20], *key_str; + int key_len; + + if (key->type == HASH_KEY_IS_LONG) { + key_len = slprintf(buf, sizeof(buf) - 1, "%ld", key->num) + 1; + key_str = &buf[0]; + } else { + key_len = key->len; + key_str = key->str; + } + /* check for extra */ + if (allowed_extras) { + char **ae = allowed_extras; + + for (; *ae; ++ae) { + if (!strncasecmp(key_str, *ae, key_len)) { + if (key->type == HASH_KEY_IS_LONG) { + zend_hash_index_update(&list->extras, key->num, (void *) &arg, sizeof(zval *), NULL); + } else { + zend_hash_update(&list->extras, key->str, key->len, (void *) &arg, sizeof(zval *), NULL); + } + return; + } + } + } + + /* cookie */ + if (key->type == HASH_KEY_IS_LONG) { + zend_hash_index_update(&list->cookies, key->num, (void *) &arg, sizeof(zval *), NULL); + } else { + zend_hash_update(&list->cookies, key->str, key->len, (void *) &arg, sizeof(zval *), NULL); + } + } +} + 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 TSRMLS_DC) { php_http_params_opts_t opts; @@ -134,65 +191,11 @@ PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_parse(php_http_cookie_ FOREACH_HASH_KEYVAL(pos1, ¶ms, key, param) { if (Z_TYPE_PP(param) == IS_ARRAY) { if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(param), ZEND_STRS("value"), (void *) &val)) { - Z_ADDREF_PP(val); - if (key.type == HASH_KEY_IS_STRING) { - zend_hash_update(&list->cookies, key.str, key.len, (void *) val, sizeof(zval *), NULL); - } else { - zend_hash_index_update(&list->cookies, key.num, (void *) val, sizeof(zval *), NULL); - } + add_entry(list, NULL, flags, &key, *val); } if (SUCCESS == zend_hash_find(Z_ARRVAL_PP(param), ZEND_STRS("arguments"), (void *) &args) && Z_TYPE_PP(args) == IS_ARRAY) { FOREACH_KEYVAL(pos2, *args, key, arg) { - if (key.type == HASH_KEY_IS_STRING) { - zval *tmp = php_http_ztyp(IS_STRING, *arg); - char *arg_str = Z_STRVAL_P(tmp); - size_t arg_len = Z_STRLEN_P(tmp); -#define _KEY_IS(s) (key.len == sizeof(s) && !strncasecmp(key.str, (s), key.len)) - if _KEY_IS("path") { - STR_SET(list->path, estrndup(arg_str, arg_len)); - } else if _KEY_IS("domain") { - STR_SET(list->domain, estrndup(arg_str, arg_len)); - } else if _KEY_IS("expires") { - char *date = estrndup(arg_str, arg_len); - list->expires = php_parse_date(date, NULL); - efree(date); - } else if _KEY_IS("secure") { - list->flags |= PHP_HTTP_COOKIE_SECURE; - } else if _KEY_IS("httpOnly") { - list->flags |= PHP_HTTP_COOKIE_HTTPONLY; - } else { - /* check for extra */ - if (allowed_extras) { - char **ae = allowed_extras; - - for (; *ae; ++ae) { - if (!strncasecmp(key.str, *ae, key.len)) { - if (flags & PHP_HTTP_COOKIE_PARSE_RAW) { - php_http_cookie_list_add_extra(list, key.str, key.len, arg_str, arg_len); - } else { - char *dec = estrndup(arg_str, arg_len); - int declen = php_url_decode(dec, arg_len); - - php_http_cookie_list_add_extra(list, key.str, key.len, dec, declen); - efree(dec); - } - continue; - } - } - } - /* new cookie */ - if (flags & PHP_HTTP_COOKIE_PARSE_RAW) { - php_http_cookie_list_add_cookie(list, key.str, key.len, arg_str, arg_len); - } else { - char *dec = estrndup(arg_str, arg_len); - int declen = php_url_decode(dec, arg_len); - - php_http_cookie_list_add_cookie(list, key.str, key.len, dec, declen); - efree(dec); - } - } - zval_ptr_dtor(&tmp); - } + add_entry(list, allowed_extras, flags, &key, *arg); } } } @@ -240,44 +243,24 @@ PHP_HTTP_API php_http_cookie_list_t *php_http_cookie_list_from_struct(php_http_c zend_hash_copy(&list->extras, Z_ARRVAL_PP(tmp), (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *)); } if (SUCCESS == zend_hash_find(ht, "flags", sizeof("flags"), (void *) &tmp)) { - switch (Z_TYPE_PP(tmp)) { - case IS_LONG: - list->flags = Z_LVAL_PP(tmp); - break; - case IS_DOUBLE: - list->flags = (long) Z_DVAL_PP(tmp); - break; - case IS_STRING: - cpy = php_http_ztyp(IS_LONG, *tmp); - list->flags = Z_LVAL_P(cpy); - zval_ptr_dtor(&cpy); - break; - default: - break; - } + cpy = php_http_ztyp(IS_LONG, *tmp); + list->flags = Z_LVAL_P(cpy); + zval_ptr_dtor(&cpy); } if (SUCCESS == zend_hash_find(ht, "expires", sizeof("expires"), (void *) &tmp)) { - switch (Z_TYPE_PP(tmp)) { - case IS_LONG: - list->expires = Z_LVAL_PP(tmp); - break; - case IS_DOUBLE: - list->expires = (long) Z_DVAL_PP(tmp); - break; - case IS_STRING: - cpy = php_http_ztyp(IS_LONG, *tmp); - if (Z_LVAL_P(cpy)) { - list->expires = Z_LVAL_P(cpy); - } else { - time_t expires = php_parse_date(Z_STRVAL_PP(tmp), NULL); - if (expires > 0) { - list->expires = expires; - } - } - zval_ptr_dtor(&cpy); - break; - default: - break; + if (Z_TYPE_PP(tmp) == IS_LONG) { + list->expires = Z_LVAL_PP(tmp); + } else { + long lval; + + cpy = php_http_ztyp(IS_STRING, *tmp); + if (IS_LONG == is_numeric_string(Z_STRVAL_P(cpy), Z_STRLEN_P(cpy), &lval, NULL, 0)) { + list->expires = lval; + } else { + list->expires = php_parse_date(Z_STRVAL_P(cpy), NULL); + } + + zval_ptr_dtor(&cpy); } } if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &tmp) && Z_TYPE_PP(tmp) == IS_STRING) { @@ -297,8 +280,8 @@ static inline void append_encoded(php_http_buffer_t *buf, const char *key, size_ char *enc_str[2]; int enc_len[2]; - enc_str[0] = php_url_encode(key, key_len, &enc_len[0]); - enc_str[1] = php_url_encode(val, val_len, &enc_len[1]); + enc_str[0] = php_raw_url_encode(key, key_len, &enc_len[0]); + enc_str[1] = php_raw_url_encode(val, val_len, &enc_len[1]); php_http_buffer_append(buf, enc_str[0], enc_len[0]); php_http_buffer_appends(buf, "="); @@ -322,11 +305,17 @@ PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, c php_http_buffer_init(&buf); FOREACH_HASH_KEYVAL(pos, &list->cookies, key, val) { + zval *tmp = php_http_ztyp(IS_STRING, *val); if (key.type == HASH_KEY_IS_STRING && key.len) { - zval *tmp = php_http_ztyp(IS_STRING, *val); append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); - zval_ptr_dtor(&tmp); + } else if (key.type == HASH_KEY_IS_LONG) { + int enc_len; + char *enc_str = php_raw_url_encode(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &enc_len); + + php_http_buffer_appendf(&buf, "%ld=%.*s; ", key.num, enc_len, enc_str); + efree(enc_str); } + zval_ptr_dtor(&tmp); } if (list->domain && *list->domain) { @@ -335,18 +324,24 @@ PHP_HTTP_API void php_http_cookie_list_to_string(php_http_cookie_list_t *list, c if (list->path && *list->path) { php_http_buffer_appendf(&buf, "path=%s; ", list->path); } - if (list->expires) { + if (list->expires >= 0) { char *date = php_format_date(ZEND_STRL(PHP_HTTP_DATE_FORMAT), list->expires, 0 TSRMLS_CC); php_http_buffer_appendf(&buf, "expires=%s; ", date); efree(date); } FOREACH_HASH_KEYVAL(pos, &list->extras, key, val) { + zval *tmp = php_http_ztyp(IS_STRING, *val); if (key.type == HASH_KEY_IS_STRING && key.len) { - zval *tmp = php_http_ztyp(IS_STRING, *val); append_encoded(&buf, key.str, key.len-1, Z_STRVAL_P(tmp), Z_STRLEN_P(tmp)); - zval_ptr_dtor(&tmp); + } else if (key.type == HASH_KEY_IS_LONG) { + int enc_len; + char *enc_str = php_raw_url_encode(Z_STRVAL_P(tmp), Z_STRLEN_P(tmp), &enc_len); + + php_http_buffer_appendf(&buf, "%ld=%.*s; ", key.num, enc_len, enc_str); + efree(enc_str); } + zval_ptr_dtor(&tmp); } if (list->flags & PHP_HTTP_COOKIE_SECURE) { @@ -542,8 +537,17 @@ PHP_METHOD(HttpCookie, __construct) } switch (Z_TYPE_P(zcookie)) { - case IS_ARRAY: case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(zcookie), php_http_cookie_class_entry TSRMLS_CC)) { + php_http_cookie_object_t *zco = zend_object_store_get_object(zcookie TSRMLS_CC); + + 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 TSRMLS_CC); break; default: { @@ -678,8 +682,8 @@ PHP_METHOD(HttpCookie, getCookie) PHP_METHOD(HttpCookie, setCookie) { - char *name_str, *value_str; - int name_len, value_len; + char *name_str, *value_str = NULL; + int name_len, value_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len)) { php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); @@ -740,8 +744,8 @@ PHP_METHOD(HttpCookie, getExtra) PHP_METHOD(HttpCookie, setExtra) { - char *name_str, *value_str; - int name_len, value_len; + char *name_str, *value_str = NULL; + int name_len, value_len = 0; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!", &name_str, &name_len, &value_str, &value_len)) { php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); @@ -860,7 +864,7 @@ PHP_METHOD(HttpCookie, getExpires) PHP_METHOD(HttpCookie, setExpires) { - long ts = 0; + long ts = -1; if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &ts)) { php_http_cookie_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); diff --git a/php_http_params.c b/php_http_params.c index 54ef493..a8b8d2d 100644 --- a/php_http_params.c +++ b/php_http_params.c @@ -56,30 +56,32 @@ static void push_param(HashTable *params, php_http_params_state_t *state, const INIT_PZVAL(&key); php_trim(state->arg.str, state->arg.len, NULL, 0, &key, 3 TSRMLS_CC); - MAKE_STD_ZVAL(val); - ZVAL_TRUE(val); - zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.val); - + if (Z_STRLEN(key)) { + MAKE_STD_ZVAL(val); + ZVAL_TRUE(val); + zend_symtable_update(Z_ARRVAL_PP(state->current.args), Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &val, sizeof(zval *), (void *) &state->current.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; - MAKE_STD_ZVAL(prm); - array_init(prm); - MAKE_STD_ZVAL(val); - ZVAL_TRUE(val); - zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val); - - MAKE_STD_ZVAL(arg); - array_init(arg); - zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args); - INIT_PZVAL(&key); php_trim(state->param.str, state->param.len, NULL, 0, &key, 3 TSRMLS_CC); - zend_symtable_update(params, Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param); - + if (Z_STRLEN(key)) { + MAKE_STD_ZVAL(prm); + array_init(prm); + MAKE_STD_ZVAL(val); + ZVAL_TRUE(val); + zend_hash_update(Z_ARRVAL_P(prm), "value", sizeof("value"), (void *) &val, sizeof(zval *), (void *) &state->current.val); + + MAKE_STD_ZVAL(arg); + array_init(arg); + zend_hash_update(Z_ARRVAL_P(prm), "arguments", sizeof("arguments"), (void *) &arg, sizeof(zval *), (void *) &state->current.args); + + zend_symtable_update(params, Z_STRVAL(key), Z_STRLEN(key) + 1, (void *) &prm, sizeof(zval *), (void *) &state->current.param); + } zval_dtor(&key); } } diff --git a/phpunit/CookieTest.php b/phpunit/CookieTest.php new file mode 100644 index 0000000..a1a75db --- /dev/null +++ b/phpunit/CookieTest.php @@ -0,0 +1,179 @@ + array(), + "extras" => array(), + "flags" => 0, + "expires" => -1, + "path" => "", + "domain" => "" + ); + $this->assertEquals($a, $c->toArray()); + $this->assertEquals($a, $o->toArray()); + } + + function testExpiresAsDate() { + $d = new DateTime; + $c = new http\Cookie(array("expires" => $d->format(DateTime::RFC1123))); + $this->assertEquals($d->format("U"), $c->getExpires()); + } + + function testNumeric() { + $c = new http\Cookie("1=%20; 2=%22; 3=%5D", 0, array(2)); + $this->assertEquals("1=%20; 3=%5D; 2=%22; ", (string) $c); + } + + function testRaw() { + $c = new http\Cookie("1=%20; 2=%22; e3=%5D", http\Cookie::PARSE_RAW, array(2)); + $this->assertEquals("1=%2520; e3=%255D; 2=%2522; ", (string) $c); + } + + function testSimple() { + $orig = new http\Cookie("key=value"); + $copy = clone $orig; + $same = new http\Cookie($copy); + $even = new http\Cookie($same->toArray()); + foreach (array($orig, $copy) as $c) { + $this->assertEquals("value", $c->getCookie("key")); + $this->assertEquals(-1, $c->getExpires()); + $this->assertEquals(0, $c->getFlags()); + $this->assertEquals(null, $c->getPath()); + $this->assertEquals(null, $c->getDomain()); + $this->assertEquals(array(), $c->getExtras()); + $this->assertEquals(array("key" => "value"), $c->getCookies()); + $this->assertEquals("key=value; ", $c->toString()); + $this->assertEquals( + array ( + "cookies" => + array ( + "key" => "value", + ), + "extras" => + array ( + ), + "flags" => 0, + "expires" => -1, + "path" => "", + "domain" => "", + ), + $c->toArray() + ); + } + } + + function testExpires() { + $c = new http\Cookie("this=expires; expires=Tue, 24 Jan 2012 10:35:32 +0100"); + $this->assertEquals("expires", $c->getCookie("this")); + $this->assertEquals(1327397732, $c->getExpires()); + $o = clone $c; + $t = time(); + $o->setExpires(); + $this->assertEquals(-1, $o->getExpires()); + $this->assertNotEquals(-1, $c->getExpires()); + $o->setExpires($t); + $this->assertEquals($t, $o->getExpires()); + $this->assertNotEquals($t, $c->getExpires()); + $this->assertEquals( + sprintf( + "this=expires; expires=%s; ", + date_create("@$t")->format("D, d M Y H:i:s \\G\\M\\T") + ), + $o->toString() + ); + } + + function testPath() { + $c = new http\Cookie("this=has a path; path=/down; "); + $this->assertEquals("has a path", $c->getCookie("this")); + $this->assertEquals("this=has%20a%20path; path=/down; ", (string)$c); + $this->assertEquals("/down", $c->getPath()); + $o = clone $c; + $p = "/up"; + $o->setPath(); + $this->assertEquals(null, $o->getPath()); + $this->assertNotEquals(null, $c->getPath()); + $o->setPath($p); + $this->assertEquals($p, $o->getPath()); + $this->assertNotEquals($p, $c->getPath()); + $this->assertEquals("this=has%20a%20path; path=$p; ", $o->toString()); + } + + function testDomain() { + $c = new http\Cookie("this=has a domain; domain=.example.com; "); + $this->assertEquals("has a domain", $c->getCookie("this")); + $this->assertEquals("this=has%20a%20domain; domain=.example.com; ", (string)$c); + $this->assertEquals(".example.com", $c->getDomain()); + $o = clone $c; + $d = "sub.example.com"; + $o->setDomain(); + $this->assertEquals(null, $o->getDomain()); + $this->assertNotEquals(null, $c->getDomain()); + $o->setDomain($d); + $this->assertEquals($d, $o->getDomain()); + $this->assertNotEquals($d, $c->getDomain()); + $this->assertEquals("this=has%20a%20domain; domain=$d; ", $o->toString()); + } + + function testFlags() { + $c = new http\Cookie("icanhas=flags; secure; httpOnly"); + $this->assertEquals(http\Cookie::SECURE, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $c->setFlags($c->getFlags() ^ http\Cookie::SECURE); + $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(http\Cookie::HTTPONLY, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $c->setFlags($c->getFlags() ^ http\Cookie::HTTPONLY); + $this->assertEquals(0, $c->getFlags() & http\Cookie::SECURE, "secure"); + $this->assertEquals(0, $c->getFlags() & http\Cookie::HTTPONLY, "httpOnly"); + $this->assertEquals("icanhas=flags; ", $c->toString()); + $c->setFlags(http\Cookie::SECURE|http\Cookie::HTTPONLY); + $this->assertEquals("icanhas=flags; secure; httpOnly; ", $c->toString()); + } + + function testExtras() { + $c = new http\Cookie("c1=v1; e0=1; e2=2; c2=v2", 0, array("e0", "e1", "e2")); + $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getCookies()); + $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getExtras()); + $c->addExtra("e1", 1); + $c->setExtra("e0"); + $c->setExtra("e3", 123); + $this->assertEquals(123, $c->getExtra("e3")); + $c->setExtra("e3"); + $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; ", $c->toString()); + $c->addExtras(array("e3"=>3, "e4"=>4)); + $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e2=2; e1=1; e3=3; e4=4; ", $c->toString()); + $c->setExtras(array("e"=>"x")); + $this->assertEquals(array("e"=>"x"), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; e=x; ", $c->toString()); + $c->setExtras(); + $this->assertEquals(array(), $c->getExtras()); + $this->assertEquals("c1=v1; c2=v2; ", $c->toString()); + } + + function testCookies() { + $c = new http\Cookie("e0=1; c1=v1; e2=2; c2=v2", 0, array("c0", "c1", "c2")); + $this->assertEquals(array("c1"=>"v1", "c2"=>"v2"), $c->getExtras()); + $this->assertEquals(array("e0"=>"1", "e2"=>"2"), $c->getCookies()); + $c->addCookie("e1", 1); + $c->setCookie("e0"); + $c->setCookie("e3", 123); + $this->assertEquals(123, $c->getCookie("e3")); + $c->setCookie("e3"); + $this->assertEquals(array("e2"=>"2", "e1"=>1), $c->getCookies()); + $this->assertEquals("e2=2; e1=1; c1=v1; c2=v2; ", $c->toString()); + $c->addCookies(array("e3"=>3, "e4"=>4)); + $this->assertEquals(array("e2"=>"2", "e1"=>1, "e3"=>3, "e4"=>4), $c->getCookies()); + $this->assertEquals("e2=2; e1=1; e3=3; e4=4; c1=v1; c2=v2; ", $c->toString()); + $c->setCookies(array("e"=>"x")); + $this->assertEquals(array("e"=>"x"), $c->getCookies()); + $this->assertEquals("e=x; c1=v1; c2=v2; ", $c->toString()); + $c->setCookies(); + $this->assertEquals(array(), $c->getCookies()); + $this->assertEquals("c1=v1; c2=v2; ", $c->toString()); + } +} -- 2.30.2 From 179b9e4d1c888871a3393a6045dfb675a14b6675 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 25 Jan 2012 14:41:48 +0000 Subject: [PATCH 11/16] querystring test & fix --- php_http_querystring.c | 15 ++++----- phpunit/QueryStringTest.php | 66 +++++++++++++++++++++++++++++++++++++ tests/phpunit.phpt | 2 +- 3 files changed, 74 insertions(+), 9 deletions(-) create mode 100644 phpunit/QueryStringTest.php diff --git a/php_http_querystring.c b/php_http_querystring.c index ead598b..7c569de 100644 --- a/php_http_querystring.c +++ b/php_http_querystring.c @@ -145,23 +145,22 @@ PHP_HTTP_API STATUS php_http_querystring_update(zval *qarray, zval *params, zval } } } else { + zval *entry; /* * add */ if (Z_TYPE_PP(params_entry) == IS_OBJECT) { - zval *new_array; - - MAKE_STD_ZVAL(new_array); - array_init(new_array); - php_http_querystring_update(new_array, *params_entry, NULL TSRMLS_CC); - *params_entry = new_array; + MAKE_STD_ZVAL(entry); + array_init(entry); + php_http_querystring_update(entry, *params_entry, NULL TSRMLS_CC); } else { Z_ADDREF_PP(params_entry); + entry = *params_entry; } if (key.type == HASH_KEY_IS_STRING) { - add_assoc_zval_ex(qarray, key.str, key.len, *params_entry); + add_assoc_zval_ex(qarray, key.str, key.len, entry); } else { - add_index_zval(qarray, key.num, *params_entry); + add_index_zval(qarray, key.num, entry); } } } diff --git a/phpunit/QueryStringTest.php b/phpunit/QueryStringTest.php new file mode 100644 index 0000000..2fde23a --- /dev/null +++ b/phpunit/QueryStringTest.php @@ -0,0 +1,66 @@ +q = new http\QueryString($this->s); + } + + function testSimple() { + $this->assertEquals($this->e, (string) $this->q); + $this->assertEquals($this->e, $this->q->get()); + } + + function testGetDefval() { + $this->assertEquals("nonexistant", $this->q->get("unknown", "s", "nonexistant")); + $this->assertEquals(null, $this->q->get("unknown")); + } + + function testGetA() { + $this->assertEquals("b", $this->q->get("a")); + $this->assertEquals(0, $this->q->get("a", "i")); + $this->assertEquals(array("b"), $this->q->get("a", "a")); + $this->assertEquals((object)array("scalar" => "b"), $this->q->get("a", "o")); + } + + function testGetR() { + $this->assertEquals(array(0,1,2), $this->q->get("r")); + } + + function testGetRR() { + $this->assertEquals(array(array("00"),array("10")), $this->q->get("rr")); + } + + function testGet1() { + $this->assertEquals(2, $this->q->get(1)); + $this->assertEquals("2", $this->q->get(1, "s")); + $this->assertEquals(2.0, $this->q->get(1, "f")); + $this->assertTrue($this->q->get(1, "b")); + } + + function testDelA() { + $this->assertEquals("b", $this->q->get("a", http\QueryString::TYPE_STRING, null, true)); + $this->assertEquals(null, $this->q->get("a")); + } + + function testDelAll() { + $this->q->set(array("a" => null, "r" => null, "rr" => null, 1 => null)); + $this->assertEquals("", $this->q->toString()); + } + + function testQSO() { + $this->assertEquals($this->e, (string) new http\QueryString($this->q)); + $this->assertEquals(http_build_query(array("e"=>$this->q->toArray())), (string) new http\QueryString(array("e" => $this->q))); + } + + function testIterator() { + $this->assertEquals($this->q->toArray(), iterator_to_array($this->q)); + } + + function testSerialize() { + $this->assertEquals($this->e, (string) unserialize(serialize($this->q))); + } +} diff --git a/tests/phpunit.phpt b/tests/phpunit.phpt index 4289ffd..6320f61 100644 --- a/tests/phpunit.phpt +++ b/tests/phpunit.phpt @@ -12,7 +12,7 @@ require_once "PHPUnit/Autoload.php"; --EXPECTF-- PHPUnit %s by Sebastian Bergmann. -%s +%a Time: %s, Memory: %s -- 2.30.2 From d926a12aeec96752456eddfbf9a04a002809a0d2 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 1 Feb 2012 09:21:21 +0000 Subject: [PATCH 12/16] HTTP info test & fixes --- php_http_header_parser.c | 4 +-- php_http_info.c | 27 ++--------------- php_http_info.h | 2 -- tests/info_001.phpt | 65 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 29 deletions(-) create mode 100644 tests/info_001.phpt diff --git a/php_http_header_parser.c b/php_http_header_parser.c index 975df24..0dbaf84 100644 --- a/php_http_header_parser.c +++ b/php_http_header_parser.c @@ -120,8 +120,8 @@ PHP_HTTP_API STATUS php_http_header_parser_parse(php_http_header_parser_t *parse } case PHP_HTTP_HEADER_PARSER_STATE_KEY: { - const char *colon, *eol_str; - int eol_len; + const char *colon, *eol_str = NULL; + int eol_len = 0; if (buffer->data == (eol_str = php_http_locate_bin_eol(buffer->data, buffer->used, &eol_len))) { /* end of headers */ diff --git a/php_http_info.c b/php_http_info.c index 3bde791..cc015a8 100644 --- a/php_http_info.c +++ b/php_http_info.c @@ -12,29 +12,6 @@ #include "php_http_api.h" -PHP_HTTP_API void php_http_info_default_callback(void **nothing, HashTable **headers, php_http_info_t *info TSRMLS_DC) -{ - zval array; - (void) nothing; - - INIT_PZVAL_ARRAY(&array, *headers); - - switch (info->type) { - case PHP_HTTP_REQUEST: - add_assoc_string(&array, "Request Method", PHP_HTTP_INFO(info).request.method, 1); - add_assoc_string(&array, "Request Url", PHP_HTTP_INFO(info).request.url, 1); - break; - - case PHP_HTTP_RESPONSE: - add_assoc_long(&array, "Response Code", (long) PHP_HTTP_INFO(info).response.code); - add_assoc_string(&array, "Response Status", PHP_HTTP_INFO(info).response.status, 1); - break; - - case PHP_HTTP_NONE: - break; - } -} - PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *i TSRMLS_DC) { if (!i) { @@ -134,7 +111,7 @@ PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const c } /* is request */ - else if (!http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n') { + else if (*(http - 1) == ' ' && !http[lenof("HTTP/1.x")] || http[lenof("HTTP/1.x")] == '\r' || http[lenof("HTTP/1.x")] == '\n') { const char *url = strchr(pre_header, ' '); info->type = PHP_HTTP_REQUEST; @@ -145,7 +122,7 @@ PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const c if (http > url) { PHP_HTTP_INFO(info).request.url = estrndup(url, http - url); } else { - efree(PHP_HTTP_INFO(info).request.method); + STR_SET(PHP_HTTP_INFO(info).request.method, NULL); return NULL; } } else { diff --git a/php_http_info.h b/php_http_info.h index ce65fd0..92a3f33 100644 --- a/php_http_info.h +++ b/php_http_info.h @@ -55,8 +55,6 @@ typedef struct php_http_info { typedef zend_bool (*php_http_info_callback_t)(void **callback_data, HashTable **headers, php_http_info_t *info TSRMLS_DC); -PHP_HTTP_API void php_http_info_default_callback(void **nothing, HashTable **headers, php_http_info_t *info TSRMLS_DC); - PHP_HTTP_API php_http_info_t *php_http_info_init(php_http_info_t *info TSRMLS_DC); PHP_HTTP_API php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC); PHP_HTTP_API void php_http_info_dtor(php_http_info_t *info); diff --git a/tests/info_001.phpt b/tests/info_001.phpt new file mode 100644 index 0000000..e79abd4 --- /dev/null +++ b/tests/info_001.phpt @@ -0,0 +1,65 @@ +--TEST-- +invalid HTTP info +--SKIPIF-- + +--FILE-- + +DONE +--EXPECTF-- +exception 'http\Exception' with message 'could not parse message: GET HTTP/1.1' in %s +Stack trace: +#0 %s: http\Message->__construct('GET HTTP/1.1') +#1 {main} +exception 'http\Exception' with message 'could not parse message: GET HTTP/1.123' in %s +Stack trace: +#0 %s: http\Message->__construct('GET HTTP/1.123') +#1 {main} +exception 'http\Exception' with message 'could not parse message: GETHTTP/1.1' in %s +Stack trace: +#0 %s: http\Message->__construct('GETHTTP/1.1') +#1 {main} +object(http\Message)#%d (10) { + ["errorHandling":protected]=> + NULL + ["type":protected]=> + int(1) + ["body":protected]=> + object(http\Message\Body)#%d (1) { + ["errorHandling":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 -- 2.30.2 From a4fd0a809ae831f21cbaec14e24c3d3ee0569c12 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 1 Feb 2012 09:23:26 +0000 Subject: [PATCH 13/16] remove that awkward and error prone global request datashare --- php_http.c | 7 --- php_http_api.h | 1 - php_http_curl.c | 80 +------------------------ php_http_request.c | 4 -- php_http_request.h | 1 - php_http_request_datashare.c | 113 +++++------------------------------ php_http_request_datashare.h | 17 +----- php_http_request_factory.c | 46 +------------- php_http_request_pool.c | 4 -- php_http_request_pool.h | 2 - tests/factory.phpt | 25 ++++++-- 11 files changed, 41 insertions(+), 259 deletions(-) diff --git a/php_http.c b/php_http.c index 889cb09..2cd6549 100644 --- a/php_http.c +++ b/php_http.c @@ -119,10 +119,6 @@ zend_php_http_globals *php_http_globals(void) #endif PHP_INI_BEGIN() PHP_HTTP_INI_ENTRY("http.etag.mode", "crc32b", PHP_INI_ALL, OnUpdateString, env.etag_mode) - PHP_HTTP_INI_ENTRY("http.request_datashare.cookie", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.cookie) - PHP_HTTP_INI_ENTRY("http.request_datashare.dns", "1", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.dns) - PHP_HTTP_INI_ENTRY("http.request_datashare.ssl", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.ssl) - PHP_HTTP_INI_ENTRY("http.request_datashare.connect", "0", PHP_INI_SYSTEM, OnUpdateBool, request_datashare.connect) PHP_HTTP_INI_ENTRY("http.persistent_handle.limit", "-1", PHP_INI_SYSTEM, OnUpdateLong, persistent_handle.limit) PHP_INI_END() @@ -174,7 +170,6 @@ PHP_MSHUTDOWN_FUNCTION(http) #if PHP_HTTP_HAVE_CURL || SUCCESS != PHP_MSHUTDOWN_CALL(http_curl) #endif - || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_datashare) || SUCCESS != PHP_MSHUTDOWN_CALL(http_request_factory) || SUCCESS != PHP_MSHUTDOWN_CALL(http_persistent_handle) ) { @@ -188,7 +183,6 @@ PHP_RINIT_FUNCTION(http) { if (0 || SUCCESS != PHP_RINIT_CALL(http_env) - || SUCCESS != PHP_RINIT_CALL(http_request_datashare) #if PHP_HTTP_HAVE_CURL || SUCCESS != PHP_RINIT_CALL(http_curl) #endif @@ -203,7 +197,6 @@ PHP_RSHUTDOWN_FUNCTION(http) { if (0 || SUCCESS != PHP_RSHUTDOWN_CALL(http_env) - || SUCCESS != PHP_RSHUTDOWN_CALL(http_request_datashare) ) { return FAILURE; } diff --git a/php_http_api.h b/php_http_api.h index ebb6218..50ff615 100644 --- a/php_http_api.h +++ b/php_http_api.h @@ -106,7 +106,6 @@ typedef int STATUS; ZEND_BEGIN_MODULE_GLOBALS(php_http) struct php_http_env_globals env; struct php_http_persistent_handle_globals persistent_handle; - struct php_http_request_datashare_globals request_datashare; #if PHP_HTTP_HAVE_CURL && PHP_HTTP_HAVE_EVENT struct php_http_curl_globals curl; #endif diff --git a/php_http_curl.c b/php_http_curl.c index 91b476c..2d10922 100644 --- a/php_http_curl.c +++ b/php_http_curl.c @@ -61,19 +61,8 @@ typedef struct php_http_curl_request_pool { #endif } php_http_curl_request_pool_t; -#ifdef ZTS -typedef struct php_http_curl_request_datashare_lock { - CURL *ch; - MUTEX_T mx; -} php_http_curl_request_datashare_lock_t; -#endif - typedef struct php_http_curl_request_datashare { CURLSH *handle; - -#ifdef ZTS - php_http_curl_request_datashare_lock_t *locks; -#endif } php_http_curl_request_datashare_t; #define PHP_HTTP_CURL_OPT_STRING(OPTION, ldiff, obdc) \ @@ -1148,53 +1137,6 @@ static STATUS get_info(CURL *ch, HashTable *info) } -#ifdef ZTS -static void *php_http_curl_request_datashare_locks_init(void) -{ - int i; - php_http_curl_request_datashare_lock_t *locks = pecalloc(CURL_LOCK_DATA_LAST, sizeof(*locks), 1); - - if (locks) { - for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { - locks[i].mx = tsrm_mutex_alloc(); - } - } - - return locks; -} - -static void php_http_curl_request_datashare_locks_dtor(void *l) -{ - int i; - php_http_curl_request_datashare_lock_t *locks = l; - - for (i = 0; i < CURL_LOCK_DATA_LAST; ++i) { - tsrm_mutex_free(locks[i].mx); - } - pefree(locks, 1); -} - -static void php_http_curl_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr) -{ - php_http_curl_request_datashare_lock_t *locks = userptr; - - /* TSRM can't distinguish shared/exclusive locks */ - tsrm_mutex_lock(locks[data].mx); - locks[data].ch = handle; -} - -static void php_http_curl_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr) -{ - php_http_curl_request_datashare_lock_t *locks = userptr; - - if (locks[data].ch == handle) { - tsrm_mutex_unlock(locks[data].mx); - } -} -#endif - - - /* request datashare handler ops */ static php_http_request_datashare_t *php_http_curl_request_datashare_init(php_http_request_datashare_t *h, void *handle) @@ -1207,18 +1149,8 @@ static php_http_request_datashare_t *php_http_curl_request_datashare_init(php_ht return NULL; } - curl = pecalloc(1, sizeof(*curl), h->persistent); + curl = ecalloc(1, sizeof(*curl)); curl->handle = handle; -#ifdef ZTS - if (h->persistent) { - curl->locks = php_http_curl_request_datashare_locks_init(); - if (curl->locks) { - curl_share_setopt(curl->handle, CURLSHOPT_LOCKFUNC, php_http_curl_request_datashare_lock_func); - curl_share_setopt(curl->handle, CURLSHOPT_UNLOCKFUNC, php_http_curl_request_datashare_unlock_func); - curl_share_setopt(curl->handle, CURLSHOPT_USERDATA, curl->locks); - } - } -#endif h->ctx = curl; return h; @@ -1231,13 +1163,7 @@ static void php_http_curl_request_datashare_dtor(php_http_request_datashare_t *h php_http_resource_factory_handle_dtor(h->rf, curl->handle TSRMLS_CC); -#ifdef ZTS - if (h->persistent) { - php_http_curl_request_datashare_locks_dtor(curl->locks); - } -#endif - - pefree(curl, h->persistent); + efree(curl); h->ctx = NULL; } @@ -1285,7 +1211,7 @@ static STATUS php_http_curl_request_datashare_setopt(php_http_request_datashare_ break; case PHP_HTTP_REQUEST_DATASHARE_OPT_RESOLVER: - if (CURLSHE_OK != (rc = curl_share_setopt(curl->handle, *((zend_bool *) arg) ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, CURL_LOCK_DATA_COOKIE))) { + if (CURLSHE_OK != (rc = curl_share_setopt(curl->handle, *((zend_bool *) arg) ? CURLSHOPT_SHARE : CURLSHOPT_UNSHARE, CURL_LOCK_DATA_DNS))) { TSRMLS_FETCH_FROM_CTX(h->ts); php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST_DATASHARE, "Could not %s sharing of resolver data: %s", *((zend_bool *) arg) ? "enable" : "disable", curl_share_strerror(rc)); diff --git a/php_http_request.c b/php_http_request.c index 26e87f6..b22e12e 100644 --- a/php_http_request.c +++ b/php_http_request.c @@ -52,10 +52,6 @@ PHP_HTTP_API void php_http_request_dtor(php_http_request_t *h) php_http_resource_factory_free(&h->rf); - if (h->persistent_handle_id) { - zval_ptr_dtor(&h->persistent_handle_id); - } - php_http_message_parser_free(&h->parser); php_http_message_free(&h->message); php_http_buffer_free(&h->buffer); diff --git a/php_http_request.h b/php_http_request.h index 6c0c0c9..3d7b78c 100644 --- a/php_http_request.h +++ b/php_http_request.h @@ -150,7 +150,6 @@ struct php_http_request { php_http_message_parser_t *parser; php_http_message_t *message; php_http_buffer_t *buffer; - zval *persistent_handle_id; #ifdef ZTS void ***ts; #endif diff --git a/php_http_request_datashare.c b/php_http_request_datashare.c index ce3f1a3..a4502e5 100644 --- a/php_http_request_datashare.c +++ b/php_http_request_datashare.c @@ -16,61 +16,24 @@ static int php_http_request_datashare_compare_handles(void *h1, void *h2); -#ifdef ZTS -static void *php_http_request_datashare_locks_init(void); -static void php_http_request_datashare_locks_dtor(void *l); -static void php_http_request_datashare_lock_func(CURL *handle, curl_lock_data data, curl_lock_access locktype, void *userptr); -static void php_http_request_datashare_unlock_func(CURL *handle, curl_lock_data data, void *userptr); -static MUTEX_T php_http_request_datashare_global_shares_lock; -#endif -static HashTable php_http_request_datashare_global_shares; -php_http_request_datashare_t *php_http_request_datashare_global_get(const char *driver_str, size_t driver_len TSRMLS_DC) -{ - php_http_request_datashare_t *s = NULL, **s_ptr; - char *lower_str = php_strtolower(estrndup(driver_str, driver_len), driver_len); - -#ifdef ZTS - tsrm_mutex_lock(php_http_request_datashare_global_shares_lock); -#endif - if (zend_hash_find(&php_http_request_datashare_global_shares, lower_str, driver_len + 1, (void *) &s_ptr)) { - s = *s_ptr; - } else { - php_http_request_factory_driver_t driver; - - if ((SUCCESS == php_http_request_factory_get_driver(driver_str, driver_len, &driver)) && driver.request_datashare_ops) { - s = php_http_request_datashare_init(NULL, driver.request_datashare_ops, NULL, NULL, 1 TSRMLS_CC); - zend_hash_add(&php_http_request_datashare_global_shares, lower_str, driver_len + 1, &s, sizeof(php_http_request_datashare_t *), NULL); - } - } -#ifdef ZTS - tsrm_mutex_unlock(php_http_request_datashare_global_shares_lock); -#endif - - efree(lower_str); - return s; -} - -PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *h, php_http_request_datashare_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg, zend_bool persistent TSRMLS_DC) +PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *h, php_http_request_datashare_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg TSRMLS_DC) { php_http_request_datashare_t *free_h = NULL; if (!h) { - free_h = h = pemalloc(sizeof(*h), persistent); + free_h = h = emalloc(sizeof(*h)); } memset(h, sizeof(*h), 0); - if (!(h->persistent = persistent)) { - h->requests = emalloc(sizeof(*h->requests)); - zend_llist_init(h->requests, sizeof(zval *), ZVAL_PTR_DTOR, 0); - TSRMLS_SET_CTX(h->ts); - } + zend_llist_init(&h->requests, sizeof(zval *), ZVAL_PTR_DTOR, 0); h->ops = ops; h->rf = rf ? rf : php_http_resource_factory_init(NULL, h->ops->rsrc, NULL, NULL); + TSRMLS_SET_CTX(h->ts); if (h->ops->init) { if (!(h = h->ops->init(h, init_arg))) { if (free_h) { - pefree(free_h, persistent); + efree(free_h); } } } @@ -92,21 +55,14 @@ PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t * if (h->ops->dtor) { h->ops->dtor(h); } - if (h->requests) { - zend_llist_destroy(h->requests); - pefree(h->requests, h->persistent); - h->requests = NULL; - } - - if (h->persistent_handle_id) { - zval_ptr_dtor(&h->persistent_handle_id); - } + zend_llist_destroy(&h->requests); + php_http_resource_factory_free(&h->rf); } PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **h) { php_http_request_datashare_dtor(*h); - pefree(*h, (*h)->persistent); + efree(*h); *h = NULL; } @@ -119,7 +75,7 @@ PHP_HTTP_API STATUS php_http_request_datashare_attach(php_http_request_datashare if (SUCCESS == h->ops->attach(h, obj->request)) { Z_ADDREF_P(request); - zend_llist_add_element(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), &request); + zend_llist_add_element(&h->requests, &request); return SUCCESS; } } @@ -140,7 +96,7 @@ PHP_HTTP_API STATUS php_http_request_datashare_detach(php_http_request_datashare php_http_request_object_t *obj = zend_object_store_get_object(request TSRMLS_CC); if (SUCCESS == h->ops->detach(h, obj->request)) { - zend_llist_del_element(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), request, php_http_request_datashare_compare_handles); + zend_llist_del_element(&h->requests, request, php_http_request_datashare_compare_handles); return SUCCESS; } } @@ -167,16 +123,10 @@ PHP_HTTP_API void php_http_request_datashare_reset(php_http_request_datashare_t if (h->ops->reset) { h->ops->reset(h); } else if (h->ops->detach) { - zend_llist_apply_with_argument(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h), detach, h TSRMLS_CC); + zend_llist_apply_with_argument(&h->requests, detach, h TSRMLS_CC); } - zend_llist_clean(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(h)); -} - -static void php_http_request_datashare_global_requests_dtor(void *el) -{ - //php_http_request_datashare_detach(php_http_request_datashare_global_get(), *((zval **) el)); - zval_ptr_dtor(el); + zend_llist_clean(&h->requests); } #define PHP_HTTP_BEGIN_ARGS(method, req_args) PHP_HTTP_BEGIN_ARGS_EX(HttpRequestDataShare, method, 0, req_args) @@ -227,7 +177,7 @@ zend_object_value php_http_request_datashare_object_new_ex(zend_class_entry *ce, if (share) { o->share = share; } else { - o->share = php_http_request_datashare_init(NULL, NULL, NULL, NULL, 0 TSRMLS_CC); + o->share = php_http_request_datashare_init(NULL, NULL, NULL, NULL TSRMLS_CC); } if (ptr) { @@ -244,9 +194,7 @@ void php_http_request_datashare_object_free(void *object TSRMLS_DC) { php_http_request_datashare_object_t *o = (php_http_request_datashare_object_t *) object; - if (!o->share->persistent) { - php_http_request_datashare_free(&o->share); - } + php_http_request_datashare_free(&o->share); zend_object_std_dtor((zend_object *) o TSRMLS_CC); efree(o); } @@ -311,7 +259,7 @@ PHP_METHOD(HttpRequestDataShare, count) if (SUCCESS == zend_parse_parameters_none()) { php_http_request_datashare_object_t *obj = zend_object_store_get_object(getThis() TSRMLS_CC); - RETURN_LONG(zend_llist_count(PHP_HTTP_REQUEST_DATASHARE_REQUESTS(obj->share))); + RETURN_LONG(zend_llist_count(&obj->share->requests)); } RETURN_FALSE; } @@ -364,43 +312,12 @@ PHP_MINIT_FUNCTION(http_request_datashare) zend_class_implements(php_http_request_datashare_class_entry TSRMLS_CC, 1, spl_ce_Countable); - zend_declare_property_null(php_http_request_datashare_class_entry, ZEND_STRL("instance"), (ZEND_ACC_STATIC|ZEND_ACC_PRIVATE) TSRMLS_CC); zend_declare_property_bool(php_http_request_datashare_class_entry, ZEND_STRL("cookie"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); zend_declare_property_bool(php_http_request_datashare_class_entry, ZEND_STRL("dns"), 0, ZEND_ACC_PUBLIC TSRMLS_CC); -#ifdef ZTS - php_http_request_datashare_global_shares_lock = tsrm_mutex_alloc(); -#endif - zend_hash_init(&php_http_request_datashare_global_shares, 0, NULL, (dtor_func_t) php_http_request_datashare_free, 1); - return SUCCESS; } -PHP_MSHUTDOWN_FUNCTION(http_request_datashare) -{ - zend_hash_destroy(&php_http_request_datashare_global_shares); -#ifdef ZTS - tsrm_mutex_free(php_http_request_datashare_global_shares_lock); -#endif - - return SUCCESS; -} - -PHP_RINIT_FUNCTION(http_request_datashare) -{ - zend_llist_init(&PHP_HTTP_G->request_datashare.requests, sizeof(zval *), php_http_request_datashare_global_requests_dtor, 0); - - return SUCCESS; -} - -PHP_RSHUTDOWN_FUNCTION(http_request_datashare) -{ - zend_llist_destroy(&PHP_HTTP_G->request_datashare.requests); - - return SUCCESS; -} - - /* * Local variables: * tab-width: 4 diff --git a/php_http_request_datashare.h b/php_http_request_datashare.h index 5ef6328..a6939ac 100644 --- a/php_http_request_datashare.h +++ b/php_http_request_datashare.h @@ -39,35 +39,22 @@ typedef struct php_http_request_datashare_ops { php_http_request_datashare_setopt_func_t setopt; } php_http_request_datashare_ops_t; -#define PHP_HTTP_REQUEST_DATASHARE_REQUESTS(s) ((s)->persistent ? &PHP_HTTP_G->request_datashare.requests : (s)->requests) struct php_http_request_datashare { void *ctx; php_http_resource_factory_t *rf; php_http_request_datashare_ops_t *ops; - zend_llist *requests; /* NULL if persistent, use PHP_HTTP_REQUEST_DATASHARE_REQUESTS */ - unsigned persistent:1; - zval *persistent_handle_id; + zend_llist requests; #ifdef ZTS void ***ts; #endif }; -struct php_http_request_datashare_globals { - zend_llist requests; - zend_bool cookie; - zend_bool dns; - zend_bool ssl; - zend_bool connect; -}; - -extern php_http_request_datashare_t *php_http_request_datashare_global_get(const char *driver_str, size_t driver_len TSRMLS_DC); - extern PHP_MINIT_FUNCTION(http_request_datashare); extern PHP_MSHUTDOWN_FUNCTION(http_request_datashare); extern PHP_RINIT_FUNCTION(http_request_datashare); extern PHP_RSHUTDOWN_FUNCTION(http_request_datashare); -PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *h, php_http_request_datashare_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg, zend_bool persistent TSRMLS_DC); +PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_init(php_http_request_datashare_t *h, php_http_request_datashare_ops_t *ops, php_http_resource_factory_t *rf, void *init_arg TSRMLS_DC); PHP_HTTP_API php_http_request_datashare_t *php_http_request_datashare_copy(php_http_request_datashare_t *from, php_http_request_datashare_t *to); PHP_HTTP_API void php_http_request_datashare_dtor(php_http_request_datashare_t *h); PHP_HTTP_API void php_http_request_datashare_free(php_http_request_datashare_t **h); diff --git a/php_http_request_factory.c b/php_http_request_factory.c index b1655f6..1f5f241 100644 --- a/php_http_request_factory.c +++ b/php_http_request_factory.c @@ -73,7 +73,6 @@ PHP_HTTP_BEGIN_ARGS(createDataShare, 0) PHP_HTTP_ARG_OBJ(http\\Request, request2, 1) PHP_HTTP_ARG_OBJ(http\\Request, requestN, 1) PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(getGlobalDataShareInstance); PHP_HTTP_EMPTY_ARGS(getDriver); PHP_HTTP_EMPTY_ARGS(getAvailableDrivers); @@ -83,7 +82,6 @@ zend_function_entry php_http_request_factory_method_entry[] = { PHP_HTTP_REQUEST_FACTORY_ME(createRequest, ZEND_ACC_PUBLIC) PHP_HTTP_REQUEST_FACTORY_ME(createPool, ZEND_ACC_PUBLIC) PHP_HTTP_REQUEST_FACTORY_ME(createDataShare, ZEND_ACC_PUBLIC) - PHP_HTTP_REQUEST_FACTORY_ME(getGlobalDataShareInstance, ZEND_ACC_PUBLIC) PHP_HTTP_REQUEST_FACTORY_ME(getDriver, ZEND_ACC_PUBLIC) PHP_HTTP_REQUEST_FACTORY_ME(getAvailableDrivers, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) @@ -305,7 +303,7 @@ PHP_METHOD(HttpRequestFactory, createDataShare) efree(name_str); } - share = php_http_request_datashare_init(NULL, driver.request_datashare_ops, rf, NULL, 0 TSRMLS_CC); + share = php_http_request_datashare_init(NULL, driver.request_datashare_ops, rf, NULL TSRMLS_CC); if (share) { if (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_request_datashare_object_new_ex, php_http_request_datashare_class_entry, share, NULL TSRMLS_CC)) { ZVAL_OBJVAL(return_value, ov, 0); @@ -328,48 +326,6 @@ PHP_METHOD(HttpRequestFactory, createDataShare) } end_error_handling(); } -PHP_METHOD(HttpRequestFactory, getGlobalDataShareInstance) -{ - with_error_handling(EH_THROW, php_http_exception_class_entry) { - if (SUCCESS == zend_parse_parameters_none()) { - with_error_handling(EH_THROW, php_http_exception_class_entry) { - zval *instance = *zend_std_get_static_property(php_http_request_datashare_class_entry, ZEND_STRL("instance"), 0, NULL TSRMLS_CC); - - if (Z_TYPE_P(instance) != IS_OBJECT) { - zval *zdriver; - zend_object_value ov; - zend_class_entry *class_entry; - php_http_request_datashare_t *share; - - if (!(class_entry = php_http_request_factory_get_class_entry(getThis(), ZEND_STRL("requestDataShareClass") TSRMLS_CC))) { - class_entry = php_http_request_datashare_class_entry; - } - - if ((zdriver = zend_read_property(php_http_request_factory_class_entry, getThis(), ZEND_STRL("driver"), 0 TSRMLS_CC)) - && (IS_STRING == Z_TYPE_P(zdriver)) - && (share = php_http_request_datashare_global_get(Z_STRVAL_P(zdriver), Z_STRLEN_P(zdriver) TSRMLS_CC)) - && (SUCCESS == php_http_new(&ov, class_entry, (php_http_new_t) php_http_request_datashare_object_new_ex, php_http_request_datashare_class_entry, share, NULL TSRMLS_CC)) - ) { - MAKE_STD_ZVAL(instance); - ZVAL_OBJVAL(instance, ov, 0); - zend_update_static_property(php_http_request_datashare_class_entry, ZEND_STRL("instance"), instance TSRMLS_CC); - - if (PHP_HTTP_G->request_datashare.cookie) { - zend_update_property_bool(php_http_request_datashare_class_entry, instance, ZEND_STRL("cookie"), PHP_HTTP_G->request_datashare.cookie TSRMLS_CC); - } - if (PHP_HTTP_G->request_datashare.dns) { - zend_update_property_bool(php_http_request_datashare_class_entry, instance, ZEND_STRL("dns"), PHP_HTTP_G->request_datashare.dns TSRMLS_CC); - } - } - } - - RETVAL_ZVAL(instance, 1, 0); - } end_error_handling(); - } - } end_error_handling(); -} - - PHP_METHOD(HttpRequestFactory, getDriver) { if (SUCCESS == zend_parse_parameters_none()) { diff --git a/php_http_request_pool.c b/php_http_request_pool.c index 4930122..2cf70ef 100644 --- a/php_http_request_pool.c +++ b/php_http_request_pool.c @@ -57,10 +57,6 @@ PHP_HTTP_API void php_http_request_pool_dtor(php_http_request_pool_t *h) zend_llist_clean(&h->requests.finished); zend_llist_clean(&h->requests.attached); - if (h->persistent_handle_id) { - zval_ptr_dtor(&h->persistent_handle_id); - } - php_http_resource_factory_free(&h->rf); } diff --git a/php_http_request_pool.h b/php_http_request_pool.h index 9984642..d5657a6 100644 --- a/php_http_request_pool.h +++ b/php_http_request_pool.h @@ -55,8 +55,6 @@ struct php_http_request_pool { zend_llist finished; } requests; - zval *persistent_handle_id; - #ifdef ZTS void ***ts; #endif diff --git a/tests/factory.phpt b/tests/factory.phpt index f28eda7..d80bc82 100644 --- a/tests/factory.phpt +++ b/tests/factory.phpt @@ -3,17 +3,17 @@ factory --SKIPIF-- --FILE-- createRequest(); $p = $f->createPool(); $s = $f->createDataShare(); -var_dump(array_map("get_class", array($f,$r,$p,$s))); +var_dump( + array_map("get_class", array($f,$r,$p,$s)), + $f->getDriver() +); + +foreach (array("Request", "Pool", "DataShare") as $type) { + try { + var_dump((new http\Request\Factory(array("driver" => "nonexistant")))->{"create$type"}()); + } catch (Exception $e) { + echo $e->getMessage(), "\n"; + } +} echo "Done\n"; ?> @@ -44,4 +55,8 @@ array(4) { [3]=> string(7) "MyShare" } +string(4) "curl" +requests are not supported by this driver +pools are not supported by this driver +datashares are not supported by this driver Done -- 2.30.2 From 8c69d38f5215bf073ff0a563b65c6ac067937de4 Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 13 Feb 2012 13:26:22 +0000 Subject: [PATCH 14/16] persistent handle fixes --- php_http_env.c | 12 +-- php_http_env.h | 4 +- php_http_persistent_handle.c | 151 ++++++++++++----------------------- php_http_persistent_handle.h | 6 +- php_http_request_factory.c | 24 +----- 5 files changed, 65 insertions(+), 132 deletions(-) diff --git a/php_http_env.c b/php_http_env.c index a13e797..9fd8e59 100644 --- a/php_http_env.c +++ b/php_http_env.c @@ -587,9 +587,9 @@ PHP_HTTP_BEGIN_ARGS(negotiate, 2) PHP_HTTP_ARG_VAL(result_array, 1) PHP_HTTP_END_ARGS; -PHP_HTTP_EMPTY_ARGS(persistentHandlesStat); +PHP_HTTP_EMPTY_ARGS(statPersistentHandles); -PHP_HTTP_BEGIN_ARGS(persistentHandlesClean, 0) +PHP_HTTP_BEGIN_ARGS(cleanPersistentHandles, 0) PHP_HTTP_ARG_VAL(name, 0) PHP_HTTP_ARG_VAL(ident, 0) PHP_HTTP_END_ARGS; @@ -611,8 +611,8 @@ zend_function_entry php_http_env_method_entry[] = { PHP_HTTP_ENV_ME(negotiateCharset) PHP_HTTP_ENV_ME(negotiate) - PHP_HTTP_ENV_ME(persistentHandlesStat) - PHP_HTTP_ENV_ME(persistentHandlesClean) + PHP_HTTP_ENV_ME(statPersistentHandles) + PHP_HTTP_ENV_ME(cleanPersistentHandles) EMPTY_FUNCTION_ENTRY }; @@ -810,7 +810,7 @@ PHP_METHOD(HttpEnv, negotiate) } } -PHP_METHOD(HttpEnv, persistentHandlesStat) +PHP_METHOD(HttpEnv, statPersistentHandles) { if (SUCCESS == zend_parse_parameters_none()) { object_init(return_value); @@ -822,7 +822,7 @@ PHP_METHOD(HttpEnv, persistentHandlesStat) RETURN_FALSE; } -PHP_METHOD(HttpEnv, persistentHandlesClean) +PHP_METHOD(HttpEnv, cleanPersistentHandles) { char *name_str = NULL, *ident_str = NULL; int name_len = 0, ident_len = 0; diff --git a/php_http_env.h b/php_http_env.h index 64cc702..493f1e0 100644 --- a/php_http_env.h +++ b/php_http_env.h @@ -84,8 +84,8 @@ PHP_METHOD(HttpEnv, negotiateCharset); PHP_METHOD(HttpEnv, negotiateEncoding); PHP_METHOD(HttpEnv, negotiateContentType); PHP_METHOD(HttpEnv, negotiate); -PHP_METHOD(HttpEnv, persistentHandlesStat); -PHP_METHOD(HttpEnv, persistentHandlesClean); +PHP_METHOD(HttpEnv, statPersistentHandles); +PHP_METHOD(HttpEnv, cleanPersistentHandles); extern zend_class_entry *php_http_env_request_class_entry; extern zend_function_entry php_http_env_request_method_entry[]; diff --git a/php_http_persistent_handle.c b/php_http_persistent_handle.c index 5842035..4210437 100644 --- a/php_http_persistent_handle.c +++ b/php_http_persistent_handle.c @@ -60,21 +60,33 @@ static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list return list; } -static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t *list, php_http_persistent_handle_provider_t *provider TSRMLS_DC) +static int php_http_persistent_handle_apply_cleanup_ex(void *pp, void *arg TSRMLS_DC) { - HashPosition pos; - void **handle; - + php_http_resource_factory_t *rf = arg; + void **handle = pp; + #if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "LSTDTOR: %p\n", list); + fprintf(stderr, "DESTROY: %p\n", *handle); #endif - FOREACH_HASH_VAL(pos, &list->free, handle) { + php_http_resource_factory_handle_dtor(rf, *handle TSRMLS_CC); + return ZEND_HASH_APPLY_REMOVE; +} + +static int php_http_persistent_handle_apply_cleanup(void *pp, void *arg TSRMLS_DC) +{ + php_http_resource_factory_t *rf = arg; + php_http_persistent_handle_list_t **listp = pp; + + zend_hash_apply_with_argument(&(*listp)->free, php_http_persistent_handle_apply_cleanup_ex, rf TSRMLS_CC); + return (*listp)->used ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE; +} + +static inline void php_http_persistent_handle_list_dtor(php_http_persistent_handle_list_t *list, php_http_persistent_handle_provider_t *provider TSRMLS_DC) +{ #if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "DESTROY: %p\n", *handle); + fprintf(stderr, "LSTDTOR: %p\n", list); #endif - - provider->rf.fops.dtor(provider->rf.data, *handle TSRMLS_CC); - } + zend_hash_apply_with_argument(&list->free, php_http_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); zend_hash_destroy(&list->free); } @@ -88,6 +100,12 @@ static inline void php_http_persistent_handle_list_free(php_http_persistent_hand *list = NULL; } +static int php_http_persistent_handle_list_apply_dtor(void *listp, void *provider TSRMLS_DC) +{ + php_http_persistent_handle_list_free(listp, provider TSRMLS_CC); + return ZEND_HASH_APPLY_REMOVE; +} + static inline php_http_persistent_handle_list_t *php_http_persistent_handle_list_find(php_http_persistent_handle_provider_t *provider, const char *ident_str, size_t ident_len TSRMLS_DC) { php_http_persistent_handle_list_t **list, *new_list; @@ -124,7 +142,7 @@ static inline STATUS php_http_persistent_handle_do_acquire(php_http_persistent_h *handle = *handle_ptr; zend_hash_index_del(&list->free, index); } else { - *handle = provider->rf.fops.ctor(provider->rf.data TSRMLS_CC); + *handle = php_http_resource_factory_handle_ctor(&provider->rf TSRMLS_CC); } if (*handle) { @@ -145,7 +163,7 @@ static inline STATUS php_http_persistent_handle_do_release(php_http_persistent_h if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) { if (provider->list.used >= PHP_HTTP_G->persistent_handle.limit) { - provider->rf.fops.dtor(provider->rf.data, *handle TSRMLS_CC); + php_http_resource_factory_handle_dtor(&provider->rf, *handle TSRMLS_CC); } else { if (SUCCESS != zend_hash_next_index_insert(&list->free, (void *) handle, sizeof(void *), NULL)) { return FAILURE; @@ -165,7 +183,7 @@ static inline STATUS php_http_persistent_handle_do_accrete(php_http_persistent_h { php_http_persistent_handle_list_t *list; - if (provider->rf.fops.copy && (*new_handle = provider->rf.fops.copy(provider->rf.data, old_handle TSRMLS_CC))) { + if ((*new_handle = php_http_resource_factory_handle_copy(&provider->rf, old_handle TSRMLS_CC))) { if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) { ++list->used; } @@ -178,16 +196,9 @@ static inline STATUS php_http_persistent_handle_do_accrete(php_http_persistent_h static void php_http_persistent_handles_hash_dtor(void *p) { php_http_persistent_handle_provider_t *provider = (php_http_persistent_handle_provider_t *) p; - php_http_persistent_handle_list_t **list, *list_tmp; - HashPosition pos; TSRMLS_FETCH(); - FOREACH_HASH_VAL(pos, &provider->list.free, list) { - /* fix shutdown crash in PHP4 */ - list_tmp = *list; - php_http_persistent_handle_list_free(&list_tmp, provider TSRMLS_CC); - } - + zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_list_apply_dtor, provider TSRMLS_CC); zend_hash_destroy(&provider->list.free); php_http_resource_factory_dtor(&provider->rf); } @@ -255,13 +266,13 @@ PHP_HTTP_API php_http_persistent_handle_factory_t *php_http_persistent_handle_co } } else { if (free_a) { - efree(a); + efree(free_a); } a = NULL; } #if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "CONCETE: %p (%s) (%s)\n", a ? a->provider : NULL, name_str, ident_str); + fprintf(stderr, "CONCEDE: %p (%s) (%s)\n", a ? a->provider : NULL, name_str, ident_str); #endif return a; @@ -291,7 +302,7 @@ PHP_HTTP_API void *php_http_persistent_handle_acquire(php_http_persistent_handle PHP_HTTP_API void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t *a, void *handle TSRMLS_DC) { - void *new_handle; + void *new_handle = NULL; LOCK(); php_http_persistent_handle_do_accrete(a->provider, a->ident.str, a->ident.len, handle, &new_handle TSRMLS_CC); @@ -307,98 +318,32 @@ PHP_HTTP_API void php_http_persistent_handle_release(php_http_persistent_handle_ UNLOCK(); } -PHP_HTTP_API STATUS php_http_persistent_handle_acquire2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC) -{ - STATUS status = FAILURE; - php_http_persistent_handle_provider_t *provider; - - *handle = NULL; - LOCK(); - if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) { - status = php_http_persistent_handle_do_acquire(provider, ident_str, ident_len, handle TSRMLS_CC); - } - UNLOCK(); - -#if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "ACQUIRE: %p (%s)\n", *handle, name_str); -#endif - - return status; -} - -PHP_HTTP_API STATUS php_http_persistent_handle_release2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC) -{ - STATUS status = FAILURE; - php_http_persistent_handle_provider_t *provider; -#if PHP_HTTP_DEBUG_PHANDLES - void *handle_tmp = *handle; -#endif - - LOCK(); - if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) { - status = php_http_persistent_handle_do_release(provider, ident_str, ident_len, handle TSRMLS_CC); - } - UNLOCK(); - -#if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "RELEASE: %p (%s)\n", handle_tmp, name_str); -#endif - - return status; -} - -PHP_HTTP_API STATUS php_http_persistent_handle_accrete2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void *old_handle, void **new_handle TSRMLS_DC) -{ - STATUS status = FAILURE; - php_http_persistent_handle_provider_t *provider; - - *new_handle = NULL; - LOCK(); - if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) { - status = php_http_persistent_handle_do_accrete(provider, ident_str, ident_len, old_handle, new_handle TSRMLS_CC); - } - UNLOCK(); - -#if PHP_HTTP_DEBUG_PHANDLES - fprintf(stderr, "ACCRETE: %p > %p (%s)\n", old_handle, *new_handle, name_str); -#endif - - return status; -} - PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len TSRMLS_DC) { php_http_persistent_handle_provider_t *provider; - php_http_persistent_handle_list_t *list, **listp; - HashPosition pos1, pos2; + php_http_persistent_handle_list_t *list; LOCK(); if (name_str && name_len) { if (SUCCESS == zend_symtable_find(&php_http_persistent_handles_hash, name_str, name_len+1, (void *) &provider)) { if (ident_str && ident_len) { if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) { - php_http_persistent_handle_list_dtor(list, provider TSRMLS_CC); - php_http_persistent_handle_list_init(list); + zend_hash_apply_with_argument(&list->free, php_http_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); } } else { - FOREACH_HASH_VAL(pos1, &provider->list.free, listp) { - php_http_persistent_handle_list_dtor(*listp, provider TSRMLS_CC); - php_http_persistent_handle_list_init(*listp); - } + zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->list.free TSRMLS_CC); } } } else { - FOREACH_HASH_VAL(pos1, &php_http_persistent_handles_hash, provider) { + HashPosition pos; + + FOREACH_HASH_VAL(pos, &php_http_persistent_handles_hash, provider) { if (ident_str && ident_len) { if ((list = php_http_persistent_handle_list_find(provider, ident_str, ident_len TSRMLS_CC))) { - php_http_persistent_handle_list_dtor(list, provider TSRMLS_CC); - php_http_persistent_handle_list_init(list); + zend_hash_apply_with_argument(&list->free, php_http_persistent_handle_apply_cleanup_ex, &provider->rf TSRMLS_CC); } } else { - FOREACH_HASH_VAL(pos2, &provider->list.free, listp) { - php_http_persistent_handle_list_dtor(*listp, provider TSRMLS_CC); - php_http_persistent_handle_list_init(*listp); - } + zend_hash_apply_with_argument(&provider->list.free, php_http_persistent_handle_apply_cleanup, &provider->list.free TSRMLS_CC); } } } @@ -442,6 +387,16 @@ PHP_HTTP_API HashTable *php_http_persistent_handle_statall(HashTable *ht TSRMLS_ return ht; } +static php_http_resource_factory_ops_t php_http_persistent_handle_rf_ops = { + (php_http_resource_factory_handle_ctor_t) php_http_persistent_handle_acquire, + (php_http_resource_factory_handle_copy_t) php_http_persistent_handle_accrete, + (php_http_resource_factory_handle_dtor_t) php_http_persistent_handle_release +}; + +PHP_HTTP_API php_http_resource_factory_ops_t *php_http_persistent_handle_resource_factory_ops(void) +{ + return &php_http_persistent_handle_rf_ops; +} /* * Local variables: diff --git a/php_http_persistent_handle.h b/php_http_persistent_handle.h index 4c43374..b94cafe 100644 --- a/php_http_persistent_handle.h +++ b/php_http_persistent_handle.h @@ -43,15 +43,11 @@ PHP_HTTP_API void *php_http_persistent_handle_acquire(php_http_persistent_handle PHP_HTTP_API void php_http_persistent_handle_release(php_http_persistent_handle_factory_t *a, void *handle TSRMLS_DC); PHP_HTTP_API void *php_http_persistent_handle_accrete(php_http_persistent_handle_factory_t *a, void *handle TSRMLS_DC); -PHP_HTTP_API php_http_resource_factory_ops_t *php_http_persistnet_handle_factory_ops(void); +PHP_HTTP_API php_http_resource_factory_ops_t *php_http_persistent_handle_resource_factory_ops(void); PHP_HTTP_API void php_http_persistent_handle_cleanup(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len TSRMLS_DC); PHP_HTTP_API HashTable *php_http_persistent_handle_statall(HashTable *ht TSRMLS_DC); -PHP_HTTP_API STATUS php_http_persistent_handle_acquire2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC); -PHP_HTTP_API STATUS php_http_persistent_handle_release2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void **handle TSRMLS_DC); -PHP_HTTP_API STATUS php_http_persistent_handle_accrete2(const char *name_str, size_t name_len, const char *ident_str, size_t ident_len, void *old_handle, void **new_handle TSRMLS_DC); - #endif /* PHP_HTTP_PERSISTENT_HANDLE_H */ /* diff --git a/php_http_request_factory.c b/php_http_request_factory.c index 1f5f241..79e348f 100644 --- a/php_http_request_factory.c +++ b/php_http_request_factory.c @@ -147,13 +147,7 @@ PHP_METHOD(HttpRequestFactory, createRequest) name_len = spprintf(&name_str, 0, "http_request.%s", Z_STRVAL_P(zdriver)); if ((pf = php_http_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi) TSRMLS_CC))) { - php_http_resource_factory_ops_t ops = { - (php_http_resource_factory_handle_ctor_t) php_http_persistent_handle_acquire, - (php_http_resource_factory_handle_copy_t) php_http_persistent_handle_accrete, - (php_http_resource_factory_handle_dtor_t) php_http_persistent_handle_release - }; - - rf = php_http_resource_factory_init(NULL, &ops, pf, (void (*)(void *)) php_http_persistent_handle_abandon); + rf = php_http_resource_factory_init(NULL, php_http_persistent_handle_resource_factory_ops(), pf, (void (*)(void *)) php_http_persistent_handle_abandon); } efree(name_str); @@ -224,13 +218,7 @@ PHP_METHOD(HttpRequestFactory, createPool) name_len = spprintf(&name_str, 0, "http_request_pool.%s", Z_STRVAL_P(zdriver)); if ((pf = php_http_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi) TSRMLS_CC))) { - php_http_resource_factory_ops_t ops = { - (php_http_resource_factory_handle_ctor_t) php_http_persistent_handle_acquire, - (php_http_resource_factory_handle_copy_t) php_http_persistent_handle_accrete, - (php_http_resource_factory_handle_dtor_t) php_http_persistent_handle_release - }; - - rf = php_http_resource_factory_init(NULL, &ops, pf, (void (*)(void *)) php_http_persistent_handle_abandon); + rf = php_http_resource_factory_init(NULL, php_http_persistent_handle_resource_factory_ops(), pf, (void (*)(void *)) php_http_persistent_handle_abandon); } efree(name_str); @@ -291,13 +279,7 @@ PHP_METHOD(HttpRequestFactory, createDataShare) name_len = spprintf(&name_str, 0, "http_request_datashare.%s", Z_STRVAL_P(zdriver)); if ((pf = php_http_persistent_handle_concede(NULL , name_str, name_len, Z_STRVAL_P(phi), Z_STRLEN_P(phi) TSRMLS_CC))) { - php_http_resource_factory_ops_t ops = { - (php_http_resource_factory_handle_ctor_t) php_http_persistent_handle_acquire, - (php_http_resource_factory_handle_copy_t) php_http_persistent_handle_accrete, - (php_http_resource_factory_handle_dtor_t) php_http_persistent_handle_release - }; - - rf = php_http_resource_factory_init(NULL, &ops, pf, (void (*)(void *)) php_http_persistent_handle_abandon); + rf = php_http_resource_factory_init(NULL, php_http_persistent_handle_resource_factory_ops(), pf, (void (*)(void *)) php_http_persistent_handle_abandon); } efree(name_str); -- 2.30.2 From e34ef0f70e4bcb816b3dbfc41aedc799ec64b04d Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 13 Feb 2012 13:27:18 +0000 Subject: [PATCH 15/16] fix cloning of http\Request; add refcount to resource factory --- php_http_request.c | 48 +++++++++++++++++++++++++++++-------- php_http_resource_factory.c | 22 +++++++++++++---- php_http_resource_factory.h | 2 ++ 3 files changed, 58 insertions(+), 14 deletions(-) diff --git a/php_http_request.c b/php_http_request.c index b22e12e..6fddae3 100644 --- a/php_http_request.c +++ b/php_http_request.c @@ -36,7 +36,7 @@ PHP_HTTP_API php_http_request_t *php_http_request_init(php_http_request_t *h, ph php_http_error(HE_WARNING, PHP_HTTP_E_REQUEST, "Could not initialize request"); if (free_h) { h->ops->dtor = NULL; - php_http_request_free(&h); + php_http_request_free(&free_h); } } } @@ -68,10 +68,30 @@ PHP_HTTP_API void php_http_request_free(php_http_request_t **h) PHP_HTTP_API php_http_request_t *php_http_request_copy(php_http_request_t *from, php_http_request_t *to) { - if (from->ops->copy) { - return from->ops->copy(from, to); + if (!from->ops->copy) { + return NULL; + } else { + TSRMLS_FETCH_FROM_CTX(from->ts); + + if (!to) { + to = ecalloc(1, sizeof(*to)); + } + + to->ops = from->ops; + if (from->rf) { + php_http_resource_factory_addref(from->rf); + to->rf = from->rf; + } else { + to->rf = php_http_resource_factory_init(NULL, to->ops->rsrc, to, NULL); + } + to->buffer = php_http_buffer_init(NULL); + to->parser = php_http_message_parser_init(NULL TSRMLS_CC); + to->message = php_http_message_init(NULL, 0 TSRMLS_CC); + + TSRMLS_SET_CTX(to->ts); + + return to->ops->copy(from, to); } - return NULL; } PHP_HTTP_API STATUS php_http_request_exec(php_http_request_t *h, php_http_request_method_t meth, const char *url, php_http_message_body_t *body) @@ -427,6 +447,9 @@ STATUS php_http_request_object_requesthandler(php_http_request_object_t *obj, zv if (Z_TYPE_P(zbody) == IS_OBJECT) { *body = ((php_http_message_body_object_t *)zend_object_store_get_object(zbody TSRMLS_CC))->body; + if (*body) { + php_stream_rewind(php_http_message_body_stream(*body)); + } } } @@ -486,7 +509,7 @@ STATUS php_http_request_object_responsehandler(php_http_request_object_t *obj, z ZVAL_OBJVAL(new_hist, ov, 0); if (Z_TYPE_P(old_hist) == IS_OBJECT) { - php_http_message_object_prepend(new_hist, old_hist, 0 TSRMLS_CC); + php_http_message_object_prepend(new_hist, old_hist, 1 TSRMLS_CC); } zend_update_property(php_http_request_class_entry, getThis(), ZEND_STRL("history"), new_hist TSRMLS_CC); @@ -1149,12 +1172,17 @@ PHP_METHOD(HttpRequest, getResponseCookies) PHP_METHOD(HttpRequest, getResponseBody) { - if (SUCCESS == zend_parse_parameters_none()) { - zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC); + with_error_handling(EH_THROW, php_http_exception_class_entry) { + if (SUCCESS == zend_parse_parameters_none()) { + zval *message = zend_read_property(php_http_request_class_entry, getThis(), ZEND_STRL("responseMessage"), 0 TSRMLS_CC); - RETURN_OBJVAL(((php_http_message_object_t *)zend_object_store_get_object(message TSRMLS_CC))->body, 1); - } - RETURN_FALSE; + if (Z_TYPE_P(message) == IS_OBJECT) { + RETURN_OBJVAL(((php_http_message_object_t *)zend_object_store_get_object(message TSRMLS_CC))->body, 1); + } else { + php_http_error(HE_WARNING, PHP_HTTP_E_RUNTIME, "HttpRequest does not contain a response message"); + } + } + } end_error_handling(); } PHP_METHOD(HttpRequest, getResponseCode) diff --git a/php_http_resource_factory.c b/php_http_resource_factory.c index 3135e47..0813755 100644 --- a/php_http_resource_factory.c +++ b/php_http_resource_factory.c @@ -24,21 +24,35 @@ PHP_HTTP_API php_http_resource_factory_t *php_http_resource_factory_init(php_htt f->data = data; f->dtor = dtor; + f->refcount = 1; + return f; } +PHP_HTTP_API unsigned php_http_resource_factory_addref(php_http_resource_factory_t *rf) +{ + return ++rf->refcount; +} + PHP_HTTP_API void php_http_resource_factory_dtor(php_http_resource_factory_t *f) { - if (f->dtor) { - f->dtor(f->data); + --f->refcount; + + if (!f->refcount) { + if (f->dtor) { + f->dtor(f->data); + } } } + PHP_HTTP_API void php_http_resource_factory_free(php_http_resource_factory_t **f) { if (*f) { php_http_resource_factory_dtor(*f); - efree(*f); - *f = NULL; + if (!(*f)->refcount) { + efree(*f); + *f = NULL; + } } } diff --git a/php_http_resource_factory.h b/php_http_resource_factory.h index df49fe7..54de8c7 100644 --- a/php_http_resource_factory.h +++ b/php_http_resource_factory.h @@ -29,9 +29,11 @@ typedef struct php_http_resource_factory { void *data; void (*dtor)(void *data); + unsigned refcount; } php_http_resource_factory_t; PHP_HTTP_API php_http_resource_factory_t *php_http_resource_factory_init(php_http_resource_factory_t *f, php_http_resource_factory_ops_t *fops, void *data, void (*dtor)(void *data)); +PHP_HTTP_API unsigned php_http_resource_factory_addref(php_http_resource_factory_t *rf); PHP_HTTP_API void php_http_resource_factory_dtor(php_http_resource_factory_t *f); PHP_HTTP_API void php_http_resource_factory_free(php_http_resource_factory_t **f); -- 2.30.2 From b80b16d3afcdd12ee21229a4bdfd8882e91aa0be Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Mon, 13 Feb 2012 13:27:46 +0000 Subject: [PATCH 16/16] fix curl crash on copy --- php_http_curl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/php_http_curl.c b/php_http_curl.c index 2d10922..65b1746 100644 --- a/php_http_curl.c +++ b/php_http_curl.c @@ -127,6 +127,7 @@ static void *php_http_curl_copy(void *opaque, void *handle TSRMLS_DC) void *ch; if ((ch = curl_easy_duphandle(handle))) { + curl_easy_reset(ch); get_storage(ch); return ch; } -- 2.30.2