Skip to content

Commit

Permalink
新增支持向 Http2 StreamId 写入多次数据帧
Browse files Browse the repository at this point in the history
  • Loading branch information
Yurunsoft committed Dec 2, 2019
1 parent 1cf00a0 commit ce15d2e
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 9 deletions.
5 changes: 5 additions & 0 deletions src/YurunHttp/Attributes.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ abstract class Attributes
*/
const HTTP2_NOT_RECV = 'http2_not_recv';

/**
* 启用 Http2 pipeline
*/
const HTTP2_PIPELINE = 'http2_pipeline';

/**
* 重定向计数
*/
Expand Down
8 changes: 2 additions & 6 deletions src/YurunHttp/Handler/Swoole.php
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public function buildRequest($request, $connection, &$http2Request)
if($isHttp2)
{
$http2Request->headers = $headers;
$http2Request->pipeline = $request->getAttribute(Attributes::HTTP2_PIPELINE, false);
}
else
{
Expand Down Expand Up @@ -311,12 +312,7 @@ private function parseCookies(&$request, $connection, $http2Request)
$cookies = $this->cookieManager->getRequestCookies($request->getUri());
if($http2Request)
{
$cookie = [];
foreach($cookies as $name => $value)
{
$cookie[] = $name . '=' . urlencode($value);
}
$request = $request->withHeader('cookie', implode(',', $cookie));
$http2Request->cookies = $cookies;
}
else
{
Expand Down
23 changes: 21 additions & 2 deletions src/YurunHttp/Http2/IHttp2Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,29 @@ public function close();
* 成功返回streamId,失败返回false
*
* @param \Yurun\Util\YurunHttp\Http\Request $request
* @param bool $dropRecvResponse
* @param bool $pipeline 默认send方法在发送请求之后,会结束当前的Http2 Stream,启用PIPELINE后,底层会保持stream流,可以多次调用write方法,向服务器发送数据帧,请参考write方法。
* @param bool $dropRecvResponse 丢弃接收到的响应数据
* @return int|bool
*/
public function send($request, $dropRecvResponse = false);
public function send($request, $pipeline = false, $dropRecvResponse = false);

/**
* 向一个流写入数据帧
*
* @param int $streamId
* @param string $data
* @param boolean $end 是否关闭流
* @return bool
*/
public function write($streamId, $data, $end = false);

/**
* 关闭一个流
*
* @param int $streamId
* @return bool
*/
public function end($streamId);

/**
* 接收数据
Expand Down
29 changes: 28 additions & 1 deletion src/YurunHttp/Http2/SwooleClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Swoole\Coroutine;
use Swoole\Coroutine\Channel;
use Yurun\Util\YurunHttp\Attributes;
use Yurun\Util\YurunHttp\Http\Psr7\Uri;

class SwooleClient implements IHttp2Client
Expand Down Expand Up @@ -128,10 +129,11 @@ public function close()
* 成功返回streamId,失败返回false
*
* @param \Yurun\Util\YurunHttp\Http\Request $request
* @param bool $pipeline 默认send方法在发送请求之后,会结束当前的Http2 Stream,启用PIPELINE后,底层会保持stream流,可以多次调用write方法,向服务器发送数据帧,请参考write方法。
* @param bool $dropRecvResponse 丢弃接收到的响应数据
* @return int|bool
*/
public function send($request, $dropRecvResponse = false)
public function send($request, $pipeline = false, $dropRecvResponse = false)
{
if('2.0' !== $request->getProtocolVersion())
{
Expand All @@ -142,6 +144,7 @@ public function send($request, $dropRecvResponse = false)
{
throw new \RuntimeException(sprintf('Current http2 connection instance just support %s://%s:%s, does not support %s', $this->ssl ? 'https' : 'http', $this->host, $this->port, $uri->__toString()));
}
$request = $request->withAttribute(Attributes::HTTP2_PIPELINE, $pipeline);
$this->handler->buildRequest($request, $this->http2Client, $http2Request);
$streamId = $this->http2Client->send($http2Request);
if(!$streamId)
Expand All @@ -155,6 +158,30 @@ public function send($request, $dropRecvResponse = false)
return $streamId;
}

/**
* 向一个流写入数据帧
*
* @param int $streamId
* @param string $data
* @param boolean $end 是否关闭流
* @return bool
*/
public function write($streamId, $data, $end = false)
{
return $this->http2Client->write($streamId, $data, $end);
}

/**
* 关闭一个流
*
* @param int $streamId
* @return bool
*/
public function end($streamId)
{
return $this->http2Client->write($streamId, '', true);
}

/**
* 接收数据
*
Expand Down
71 changes: 71 additions & 0 deletions tests/unit/Http2/SwooleHttp2Test.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,75 @@ public function testMuiltCo()
});
}

public function testPipeline1()
{
$this->call(function(){
$uri = new Uri($this->http2Host);
$client = new SwooleClient($uri->getHost(), Uri::getServerPort($uri), 'https' === $uri->getScheme());

$this->assertTrue($client->connect());

$http = new HttpRequest;
$http->protocolVersion = '2.0';
$http->timeout = 3000;

$date = strtotime('2017-03-24 17:12:14');
$data = json_encode([
'date' => $date,
]);

$request = $http->buildRequest($this->http2Host, substr($data, 0, 2));
$streamId = $client->send($request, true);
$this->assertGreaterThan(0, $streamId);
$this->assertTrue($client->write($streamId, substr($data, 2), true));
// $this->assertTrue($client->end($streamId));

$response = $client->recv($streamId);
$data = $response->json(true);

$this->assertEquals($date, isset($data['date']) ? $data['date'] : null);
$this->assertGreaterThan(1, isset($data['fd']) ? $data['fd'] : null);
$this->assertEquals('yurun', $response->getHeaderLine('trailer'));
// Swoole 4.4.12 BUG,暂时无法获取
// $this->assertEquals('niubi', $response->getHeaderLine('yurun'));
$client->close();
});
}

public function testPipeline2()
{
$this->call(function(){
$uri = new Uri($this->http2Host);
$client = new SwooleClient($uri->getHost(), Uri::getServerPort($uri), 'https' === $uri->getScheme());

$this->assertTrue($client->connect());

$http = new HttpRequest;
$http->protocolVersion = '2.0';
$http->timeout = 3000;

$date = strtotime('2017-03-24 17:12:14');
$data = json_encode([
'date' => $date,
]);

$request = $http->buildRequest($this->http2Host, substr($data, 0, 2));
$streamId = $client->send($request, true);
$this->assertGreaterThan(0, $streamId);
$this->assertTrue($client->write($streamId, substr($data, 2)));
$this->assertTrue($client->end($streamId));

$response = $client->recv($streamId);
$data = $response->json(true);

$this->assertEquals($date, isset($data['date']) ? $data['date'] : null);
$this->assertGreaterThan(1, isset($data['fd']) ? $data['fd'] : null);
$this->assertEquals('yurun', $response->getHeaderLine('trailer'));
// Swoole 4.4.12 BUG,暂时无法获取
// $this->assertEquals('niubi', $response->getHeaderLine('yurun'));

$client->close();
});
}

}

0 comments on commit ce15d2e

Please sign in to comment.