/** * Send output to browser. * * @access public */ public function send() { if ($this->body instanceof ResponseContainerInterface) { // This is a response container so we'll just pass it the // request and response instances and let it handle the rest itself $this->body->send($this->request, $this); } else { $sendBody = true; // Make sure that output buffering is enabled if (ob_get_level() === 0) { ob_start(); } // Cast body to string so that everything is rendered // before running through response filters $this->body = (string) $this->body; // Run body through the response filters foreach ($this->outputFilters as $outputFilter) { $this->body = $outputFilter($this->body); } // Check ETag if response cache is enabled if ($this->responseCache === true) { $hash = '"' . hash('sha256', $this->body) . '"'; $this->header('ETag', $hash); if (str_replace('-gzip', '', $this->request->header('if-none-match')) === $hash) { $this->status(304); $sendBody = false; } } if ($sendBody && !in_array($this->statusCode, [100, 101, 102, 204, 304])) { // Start compressed output buffering if output compression is enabled if ($this->outputCompression) { ob_start('ob_gzhandler'); } echo $this->body; // If output compression is enabled then we'll have to flush the compressed buffer // so that we can get the compressed content length when setting the content-length header if ($this->outputCompression) { ob_end_flush(); } // Add the content-length header if (!array_key_exists('transfer-encoding', $this->headers)) { $this->header('content-length', ob_get_length()); } } // Send the headers and flush the output buffer $this->sendHeaders(); ob_end_flush(); } }
/** * */ public function testHeader() { $server = $this->getServerData(); $request = new Request(['server' => $server]); $this->assertNull($request->header('bar')); $this->assertFalse($request->header('bar', false)); $this->assertEquals('keep-alive', $request->header('connection')); $this->assertEquals('keep-alive', $request->header('ConNeCtIoN')); }
/** * {@inheritdoc} */ public function send(Request $request, Response $response) { // Add headers that should always be included $response->type($this->options['content_type']); $response->header('accept-ranges', $request->isSafe() ? 'bytes' : 'none'); $response->header('content-disposition', $this->options['disposition'] . '; filename="' . $this->options['file_name'] . '"'); // Get the requested byte range $range = $request->header('range'); if ($range !== null) { $range = $this->calculateRange($range); } if ($range === false) { // Not an acceptable range so we'll just send an empty response // along with a "requested range not satisfiable" status $response->status(416); $response->sendHeaders(); } else { if ($range === null) { // No range was provided by the client so we'll just fake one for the sendFile method // and set the content-length header value to the full file size $range = ['start' => 0, 'end' => $this->fileSize - 1]; $response->header('content-length', $this->fileSize); } else { // Valid range so we'll need to tell the client which range we're sending // and set the content-length header value to the length of the byte range $response->status(206); $response->header('content-range', sprintf('bytes %s-%s/%s', $range['start'], $range['end'], $this->fileSize)); $response->header('content-length', $range['end'] - $range['start'] + 1); } // Send headers and the requested byte range $response->sendHeaders(); $this->sendFile($range['start'], $range['end']); // Execute callback if there is one if (!empty($this->options['callback'])) { $this->options['callback']($this->filePath); } } }