<email>mike@php.net</email>
<active>yes</active>
</lead>
- <date>2016-03-31</date>
+ <date>2016-08-22</date>
<version>
- <release>2.6.0</release>
+ <release>2.6.0beta1</release>
<api>2.6.0</api>
</version>
<stability>
- <release>stable</release>
+ <release>beta</release>
<api>stable</api>
</stability>
<license uri="http://copyfree.org/content/standard/licenses/2bsd/license.txt">BSD-2-Clause</license>
<notes><![CDATA[
++ Added http\Client\Curl\User interface for userland event loops
++ Added http\Url::IGNORE_ERRORS, http\Url::SILENT_ERRORS and http\Url::STDFLAGS
++ Added http\Client::setDebug(callable $debug)
++ Added http\Client\Curl\FEATURES constants and namespace
++ Added http\Client\Curl\VERSIONS constants and namespace
++ Added share_cookies and share_ssl (libcurl >= 7.23.0) options to http\Client::configure()
++ http\Client uses curl_share handles to properly share cookies and SSL/TLS sessions between requests
++ Improved configure checks for default CA bundles
++ Improved negotiation precision
+* Fixed regression introduced by http\Params::PARSE_RFC5987: negotiation using the params parser would receive param keys without the trailing asterisk, stripped by http\Params::PARSE_RFC5987.
+* Fix gh-issue #50: http\Client::dequeue() within http\Client::setDebug() causes segfault (Mike, Maik Wagner)
+* Fix gh-issue #47: http\Url: Null pointer deref in sanitize_value() (Mike, @rc0r)
+* Fix gh-issue #45: HTTP/2 response message parsing broken with libcurl >= 7.49.1 (Mike)
+* Fix gh-issue #43: Joining query with empty original variable in query (Mike, Sander Backus)
+* Fix gh-issue #42: fatal error when using punycode in URLs (Mike, Sebastian Thielen)
+* Fix gh-issue #41: Use curl_version_info_data.features when initializing options (Mike)
+* Fix gh-issue #40: determinde the SSL backend used by curl at runtime (Mike, @rcanavan)
+* Fix gh-issue #39: Notice: http\Client::enqueue(): Could not set option proxy_service_name (Mike, @rcanavan)
+* Fix gh-issue #38: Persistent curl handles: error code not properly reset (Mike, @afflerbach)
+* Fix gh-issue #36: Unexpected cookies sent if persistent_handle_id is used (Mike, @rcanavan, @afflerbach)
* Fix gh-issue #34: allow setting multiple headers with the same name (Mike, @rcanavan)
+* Fix gh-issue #33: allow setting prodyhost request option to NULL (Mike, @rcanavan)
* Fix gh-issue #31: add/improve configure checks for default CA bundle/path (Mike, @rcanavan)
]]></notes>
<contents>
<file role="src" name="php_http_client.h"/>
<file role="src" name="php_http_client_curl.c"/>
<file role="src" name="php_http_client_curl.h"/>
+ <file role="src" name="php_http_client_curl_event.c"/>
+ <file role="src" name="php_http_client_curl_event.h"/>
+ <file role="src" name="php_http_client_curl_user.c"/>
+ <file role="src" name="php_http_client_curl_user.h"/>
<file role="src" name="php_http_client_request.c"/>
<file role="src" name="php_http_client_request.h"/>
<file role="src" name="php_http_client_response.c"/>
<file role="test" name="client024.phpt"/>
<file role="test" name="client025.phpt"/>
<file role="test" name="client026.phpt"/>
+ <file role="test" name="client027.phpt"/>
+ <file role="test" name="client028.phpt"/>
+ <file role="test" name="client029.phpt"/>
<file role="test" name="clientrequest001.phpt"/>
<file role="test" name="clientrequest002.phpt"/>
<file role="test" name="clientrequest003.phpt"/>
<file role="test" name="gh-issue6.phpt"/>
<file role="test" name="gh-issue7.phpt"/>
<file role="test" name="gh-issue12.phpt"/>
+ <file role="test" name="gh-issue42.phpt"/>
+ <file role="test" name="gh-issue47.phpt"/>
+ <file role="test" name="gh-issue48.phpt"/>
+ <file role="test" name="gh-issue50.phpt"/>
<file role="test" name="header001.phpt"/>
<file role="test" name="header002.phpt"/>
<file role="test" name="header003.phpt"/>
--- /dev/null
+--TEST--
+client curl user handler
+--SKIPIF--
+<?php
+include "skipif.inc";
+skip_client_test();
+_ext("ev");
+
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+class UserHandler implements http\Client\Curl\User
+{
+ private $client;
+ private $run;
+ private $ios = [];
+ private $timeout;
+
+
+ function __construct(http\Client $client) {
+ $this->client = $client;
+ }
+
+ function init(callable $run) {
+ $this->run = $run;
+ }
+
+ function timer($timeout_ms) {
+ echo "T";
+ if (isset($this->timeout)) {
+ $this->timeout->set($timeout_ms/1000, 0);
+ $this->timeout->start();
+ } else {
+ $this->timeout = new EvTimer($timeout_ms/1000, 0, function() {
+ if (!call_user_func($this->run, $this->client)) {
+ if ($this->timeout) {
+ $this->timeout->stop();
+ $this->timeout = null;
+ }
+ }
+ });
+ }
+ }
+
+ function socket($socket, $action) {
+ echo "S";
+
+ switch ($action) {
+ case self::POLL_NONE:
+ break;
+ case self::POLL_REMOVE:
+ if (isset($this->ios[(int) $socket])) {
+ echo "U";
+ $this->ios[(int) $socket]->stop();
+ unset($this->ios[(int) $socket]);
+ }
+ break;
+
+ default:
+ $ev = 0;
+ if ($action & self::POLL_IN) {
+ $ev |= Ev::READ;
+ }
+ if ($action & self::POLL_OUT) {
+ $ev |= Ev::WRITE;
+ }
+ if (isset($this->ios[(int) $socket])) {
+ $this->ios[(int) $socket]->set($socket, $ev);
+ } else {
+ $this->ios[(int) $socket] = new EvIo($socket, $ev, function($watcher, $events) use($socket) {
+ $action = 0;
+ if ($events & Ev::READ) {
+ $action |= self::POLL_IN;
+ }
+ if ($events & Ev::WRITE) {
+ $action |= self::POLL_OUT;
+ }
+ if (!call_user_func($this->run, $this->client, $socket, $action)) {
+ if ($this->timeout) {
+ $this->timeout->stop();
+ $this->timeout = null;
+ }
+ }
+ });
+ }
+ break;
+ }
+ }
+
+ function once() {
+ throw new BadMethodCallException("this test uses Ev::run()");
+ }
+
+ function wait($timeout_ms = null) {
+ throw new BadMethodCallException("this test uses Ev::run()");
+ }
+
+ function send() {
+ throw new BadMethodCallException("this test uses Ev::run()");
+ }
+}
+
+
+include "helper/server.inc";
+
+server("proxy.inc", function($port) {
+ $client = new http\Client;
+ $client->configure([
+ "use_eventloop" => new UserHandler($client)
+ ]);
+ $client->enqueue(new http\Client\Request("GET", "http://localhost:$port/"), function($r) {
+ var_dump($r->getResponseCode());
+ });
+ Ev::run();
+});
+
+?>
+===DONE===
+--EXPECTREGEX--
+Test
+T[ST]+U+int\(200\)
+===DONE===
--- /dev/null
+--TEST--
+url errors
+--SKIPIF--
+<?php
+include "skipif.inc";
+?>
+--FILE--
+<?php
+echo "Test\n";
+
+function test($url, $flags = 0) {
+ echo "# DEFAULT\n";
+ try {
+ echo new http\Url($url, null, $flags), "\n";
+ } catch (Exception $e) {
+ echo $e->getMessage(), "\n";
+ }
+
+ echo "# IGNORE\n";
+ echo new http\Url($url, null, $flags|http\Url::IGNORE_ERRORS), "\n";
+
+ echo "# SILENT\n";
+ echo new http\Url($url, null, $flags|http\Url::SILENT_ERRORS), "\n";
+
+ echo "# IGNORE|SILENT\n";
+ echo new http\Url($url, null, $flags|http\Url::IGNORE_ERRORS|http\Url::SILENT_ERRORS), "\n";
+ echo "==========\n";
+}
+
+test("http://.foo.bar/?q=1");
+test("http://..foo.bar/i.x");
+test("http://foo..bar/i..x");
+test("http://-foo.bar");
+test("http://--foo.bar");
+test("http://f--oo.bar");
+test("htto://foo.bar/?q=%");
+test("htto://foo.bar/?q=%", http\Url::PARSE_TOPCT);
+test("http://a\xc3\xc3b");
+test("http://[foobar]:123");
+test("#/?foo=&#", http\Url::PARSE_MBUTF8);
+
+?>
+
+===DONE===
+--EXPECTF--
+Test
+# DEFAULT
+http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar/?q=1'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '.foo.bar/?q=1' in %sgh-issue48.php on line %d
+http://foo.bar/?q=1
+# SILENT
+
+# IGNORE|SILENT
+http://foo.bar/?q=1
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '..foo.bar/i.x'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 0 in '..foo.bar/i.x' in %sgh-issue48.php on line %d
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 1 in '..foo.bar/i.x' in %sgh-issue48.php on line %d
+http://foo.bar/i.x
+# SILENT
+
+# IGNORE|SILENT
+http://foo.bar/i.x
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar/i..x'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '.' at pos 4 in 'foo..bar/i..x' in %sgh-issue48.php on line %d
+http://foo.bar/i..x
+# SILENT
+
+# IGNORE|SILENT
+http://foo.bar/i..x
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '-foo.bar'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '-foo.bar' in %sgh-issue48.php on line %d
+http://foo.bar/
+# SILENT
+
+# IGNORE|SILENT
+http://foo.bar/
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '--foo.bar'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 0 in '--foo.bar' in %sgh-issue48.php on line %d
+
+Warning: http\Url::__construct(): Failed to parse host; unexpected '-' at pos 1 in '--foo.bar' in %sgh-issue48.php on line %d
+http://foo.bar/
+# SILENT
+
+# IGNORE|SILENT
+http://foo.bar/
+==========
+# DEFAULT
+http://f--oo.bar/
+# IGNORE
+http://f--oo.bar/
+# SILENT
+http://f--oo.bar/
+# IGNORE|SILENT
+http://f--oo.bar/
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' in %sgh-issue48.php on line %d
+htto://foo.bar/?q=%
+# SILENT
+
+# IGNORE|SILENT
+htto://foo.bar/?q=%
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse query; invalid percent encoding at pos 2 in 'q=%' in %sgh-issue48.php on line %d
+htto://foo.bar/?q=%25
+# SILENT
+
+# IGNORE|SILENT
+htto://foo.bar/?q=%25
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 1 in 'a%c%cb'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 1 in 'a%c%cb' in %sgh-issue48.php on line %d
+
+Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0xc3 at pos 2 in 'a%c%cb' in %sgh-issue48.php on line %d
+http://ab/
+# SILENT
+
+# IGNORE|SILENT
+http://ab/
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse hostinfo; unexpected '[' at pos 0 in '[foobar]:123'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected '[' at pos 0 in '[foobar]:123' in %sgh-issue48.php on line %d
+
+Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0x5b at pos 0 in '[foobar]:123' in %sgh-issue48.php on line %d
+
+Warning: http\Url::__construct(): Failed to parse hostinfo; unexpected byte 0x5d at pos 7 in '[foobar]:123' in %sgh-issue48.php on line %d
+http://foobar:123/
+# SILENT
+
+# IGNORE|SILENT
+http://foobar:123/
+==========
+# DEFAULT
+http\Url::__construct(): Failed to parse fragment; invalid fragment identifier at pos 7 in '/?foo=&#'
+# IGNORE
+
+Warning: http\Url::__construct(): Failed to parse fragment; invalid fragment identifier at pos 7 in '/?foo=&#' in /home/mike/src/ext-http.git/tests/gh-issue48.php on line 13
+#/?foo=&#
+# SILENT
+
+# IGNORE|SILENT
+#/?foo=&#
+==========
+
+===DONE===