public function testReceivingStreamingBodyWillResolveWithStreamingResponseIfStreamingIsEnabled() { $messageFactory = new MessageFactory(); $request = $this->getMock('Psr\\Http\\Message\\RequestInterface'); $response = $messageFactory->response(1.0, 200, 'OK', array(), $this->getMock('React\\Stream\\ReadableStreamInterface')); // mock sender to resolve promise with the given $response in response to the given $request $sender = $this->getMockBuilder('Clue\\React\\Buzz\\Io\\Sender')->disableOriginalConstructor()->getMock(); $sender->expects($this->once())->method('send')->with($this->equalTo($request))->willReturn(Promise\resolve($response)); $transaction = new Transaction($request, $sender, array('streaming' => true), $messageFactory); $promise = $transaction->send(); $response = Block\await($promise, $this->getMock('React\\EventLoop\\LoopInterface')); $this->assertEquals(200, $response->getStatusCode()); $this->assertEquals('', (string) $response->getBody()); }
/** * * @internal * @param RequestInterface $request * @param MessageFactory $messageFactory * @return PromiseInterface Promise<ResponseInterface, Exception> */ public function send(RequestInterface $request, MessageFactory $messageFactory) { $uri = $request->getUri(); // URIs are required to be absolute for the HttpClient to work if ($uri->getScheme() === '' || $uri->getHost() === '') { return Promise\reject(new \InvalidArgumentException('Sending request requires absolute URI with scheme and host')); } $body = $request->getBody(); // automatically assign a Content-Length header if the body size is known if ($body->getSize() !== null && $body->getSize() !== 0 && $request->hasHeader('Content-Length') !== null) { $request = $request->withHeader('Content-Length', $body->getSize()); } if ($body instanceof ReadableStreamInterface && $body->isReadable() && !$request->hasHeader('Content-Length')) { $request = $request->withHeader('Transfer-Encoding', 'chunked'); } $headers = array(); foreach ($request->getHeaders() as $name => $values) { $headers[$name] = implode(', ', $values); } $deferred = new Deferred(); $requestStream = $this->http->request($request->getMethod(), (string) $uri, $headers, $request->getProtocolVersion()); $requestStream->on('error', function ($error) use($deferred) { $deferred->reject($error); }); $requestStream->on('response', function (ResponseStream $responseStream) use($deferred, $messageFactory) { // apply response header values from response stream $deferred->resolve($messageFactory->response($responseStream->getVersion(), $responseStream->getCode(), $responseStream->getReasonPhrase(), $responseStream->getHeaders(), $responseStream)); }); if ($body instanceof ReadableStreamInterface) { if ($body->isReadable()) { if ($request->hasHeader('Content-Length')) { // length is known => just write to request $body->pipe($requestStream); } else { // length unknown => apply chunked transfer-encoding // this should be moved somewhere else obviously $body->on('data', function ($data) use($requestStream) { $requestStream->write(dechex(strlen($data)) . "\r\n" . $data . "\r\n"); }); $body->on('end', function () use($requestStream) { $requestStream->end("0\r\n\r\n"); }); } } else { // stream is not readable => end request without body $requestStream->end(); } } else { // body is fully buffered => write as one chunk $requestStream->end((string) $body); } return $deferred->promise(); }