Implement downloadresponse via appframework

pull/1/head
Victor Dubiniuk 10 years ago
parent 4180d66555
commit 7416b8b5d6

@ -21,8 +21,10 @@ use \OCA\Documents\Db;
use \OCA\Documents\Helper;
use \OCA\Documents\Storage;
use \OCA\Documents\Download;
use \OCA\Documents\DownloadResponse;
use \OCA\Documents\File;
use OCA\Documents\Genesis;
use \OCA\Documents\View;
class DocumentController extends Controller{
@ -84,8 +86,7 @@ class DocumentController extends Controller{
$session->load($esId);
$filename = $session->getGenesisUrl() ? $session->getGenesisUrl() : '';
$download = new Download($session->getOwner(), $filename);
$download->sendResponse();
return new DownloadResponse($this->request, $session->getOwner(), $filename);
}
/**
@ -101,11 +102,12 @@ class DocumentController extends Controller{
} else {
$fullPath = '/files' . $path;
}
$download = new Download($this->uid, $fullPath);
$download->sendResponse();
return new DownloadResponse($this->request, $this->uid, $fullPath);
}
}
/**
* @NoAdminRequired
*/

@ -1,113 +0,0 @@
<?php
/**
* ownCloud - Documents App
*
* @author Victor Dubiniuk
* @copyright 2013 Victor Dubiniuk victor.dubiniuk@gmail.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Documents;
/**
* Generic download class
*/
class Download {
/**
* Filesystem view
* @var \OC\Files\View
*/
protected $view;
/**
* Path to the File to be served, relative to the view
* @var string
*/
protected $filepath;
/**
* Subclassed object
* @var
*/
protected $instance;
/**
* Build download model according to the headers
* @param type $view - filesystem view
* @param type $filepath - path to the file relative to this view root
*/
public function __construct($owner, $filepath){
$this->filepath = $filepath;
if (isset($_SERVER['HTTP_RANGE'])) {
$this->instance = new Download\Range($owner, $filepath);
} else {
$this->instance = new Download\Simple($owner, $filepath);
}
$this->view = $this->getView($owner);
}
protected function getView($owner){
return new View('/' . $owner);
}
/**
* Send the requested content
*/
public function sendResponse(){
\OCP\Response::disableCaching();
if (!$this->fileExists()){
$this->sendNotFound();
}
$this->instance->sendResponse();
exit();
}
/**
* Get the name of the requested file
* @return String
*/
protected function getFilename(){
return basename($this->filepath);
}
/**
* Get the size of the requested file
*/
protected function getFilesize(){
return $this->view->filesize($this->filepath);
}
/**
* Get the mimetype of the requested file
* @return string
*/
protected function getMimeType(){
return $this->view->getMimeType($this->filepath);
}
/**
* Check if the requested file exists
* @return bool
*/
protected function fileExists(){
return $this->view->file_exists($this->filepath);
}
/**
* Send 404 Response
*/
protected function sendNotFound(){
header("HTTP/1.0 404 Not Found");
$tmpl = new \OCP\Template('', '404', 'guest');
$tmpl->assign('file', $this->filepath);
$tmpl->printPage();
exit;
}
}

@ -1,92 +0,0 @@
<?php
/**
* ownCloud - Documents App
*
* @author Victor Dubiniuk
* @copyright 2013 Victor Dubiniuk victor.dubiniuk@gmail.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Documents\Download;
/**
* Class processing range HTTP request (partial download)
*/
class Range extends \OCA\Documents\Download {
// Start of the range
protected $start;
// End of the range
protected $end;
/**
* Build download model to serve HTTP_RANGE
* @param type $view - filesystem view
* @param type $filepath - path to the file relative to this view root
*/
public function __construct($owner, $filepath){
$this->view = $this->getView($owner);
$this->filepath = $filepath;
}
/**
* Send the requested parts of the file
*/
public function sendResponse(){
if (!preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/', $_SERVER['HTTP_RANGE'])){
$this->sendNotSatisfiable();
}
$mimetype = $this->getMimeType();
$content = $this->view->file_get_contents($this->filepath);
$data = \OCA\Documents\Filter::read($content, $mimetype);
$size = strlen($data['content']);
$ranges = explode(',', substr($_SERVER['HTTP_RANGE'], 6));
foreach ($ranges as $range){
$parts = explode('-', $range);
if ($parts[0]==='' && $parts[1]=='') {
$this->sendNotSatisfiable();
}
if ($parts[0]==='') {
$start = $size - $parts[1];
$end = $size - 1;
}
else {
$start = $parts[0];
$end = ($parts[1]==='') ? $size - 1 : $parts[1];
}
if ($start > $end){
$this->sendNotSatisfiable();
}
$buffer = substr($data['content'], $start, $end - $start);
$md5Sum = md5($buffer);
// send the headers and data
header("Content-Length: " . ($end - $start));
header("Content-md5: " . $md5Sum);
header("Accept-Ranges: bytes");
header('Content-Range: bytes ' . $start . '-' . ($end) . '/' . $size);
header("Connection: close");
header("Content-type: " . $data['mimetype']);
header('Content-Disposition: attachment; filename=' . $this->getFilename());
\OC_Util::obEnd();
echo $buffer;
flush();
}
}
/**
* Send 416 if we can't satisfy the requested ranges
*/
protected function sendNotSatisfiable(){
header('HTTP/1.1 416 Requested Range Not Satisfiable');
header('Content-Range: bytes */' . $this->getFilesize()); // Required in 416.
exit;
}
}

@ -1,50 +0,0 @@
<?php
/**
* ownCloud - Documents App
*
* @author Victor Dubiniuk
* @copyright 2013 Victor Dubiniuk victor.dubiniuk@gmail.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Documents\Download;
/**
* Class processing complete download
*/
class Simple extends \OCA\Documents\Download {
public function __construct($owner, $filepath){
$this->view = $this->getView($owner);
$this->filepath = $filepath;
}
/**
* Send the whole file content as a response
*/
public function sendResponse(){
$mimetype = $this->getMimeType();
$content = $this->view->file_get_contents($this->filepath);
$data = \OCA\Documents\Filter::read($content, $mimetype);
header( 'Content-Type:' . $data['mimetype'] );
$encodedName = rawurlencode($this->getFilename());
if (preg_match("/MSIE/", $_SERVER["HTTP_USER_AGENT"])){
header(
'Content-Disposition: attachment; filepath="' . $encodedName . '"'
);
} else {
header('Content-Disposition: attachment; filepath*=UTF-8\'\'' . $encodedName
. '; filepath="' . $encodedName . '"');
}
header('Content-Length: ' . strlen($data['content']));
\OC_Util::obEnd();
echo $data['content'];
}
}

@ -0,0 +1,115 @@
<?php
/**
* ownCloud - Documents App
*
* @author Victor Dubiniuk
* @copyright 2014 Victor Dubiniuk victor.dubiniuk@gmail.com
*
* This file is licensed under the Affero General Public License version 3 or
* later.
*/
namespace OCA\Documents;
use \OCP\AppFramework\Http;
class DownloadResponse extends \OCP\AppFramework\Http\Response {
private $request;
private $view;
private $path;
public function __construct($request, $user, $path) {
$this->request = $request;
$this->user = $user;
$this->path = $path;
$this->view = new View('/' . $user);
if (!$this->view->file_exists($path)){
$this->setStatus(Http::STATUS_NOT_FOUND);
}
}
public function render(){
if ($this->status === Http::STATUS_NOT_FOUND){
return '';
}
$info = $this->view->getFileInfo($this->path);
$this->ETag = $info['etag'];
$content = $this->view->file_get_contents($this->path);
$data = \OCA\Documents\Filter::read($content, $info['mimetype']);
$size = strlen($data['content']);
if (!is_null($this->request->server['HTTP_RANGE'])){
$isValidRange = preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/', $this->request->server['HTTP_RANGE']);
if (!$isValidRange){
return $this->sendRangeNotSatisfiable($size);
}
$ranges = explode(',', substr($this->request->server['HTTP_RANGE'], 6));
foreach ($ranges as $range){
$parts = explode('-', $range);
if ($parts[0]==='' && $parts[1]=='') {
$this->sendNotSatisfiable($size);
}
if ($parts[0]==='') {
$start = $size - $parts[1];
$end = $size - 1;
} else {
$start = $parts[0];
$end = ($parts[1]==='') ? $size - 1 : $parts[1];
}
if ($start > $end){
$this->sendNotSatisfiable($size);
}
$buffer = substr($data['content'], $start, $end - $start);
$md5Sum = md5($buffer);
// send the headers and data
$this->addHeader('Content-Length', $end - $start);
$this->addHeader('Content-md5', $md5Sum);
$this->addHeader('Accept-Ranges', 'bytes');
$this->addHeader('Content-Range', 'bytes ' . $start . '-' . ($end) . '/' . $size);
$this->addHeader('Connection', 'close');
$this->addHeader('Content-Type', $data['mimetype']);
$this->addContentDispositionHeader();
return $buffer;
}
}
$this->addHeader('Content-Type', $data['mimetype']);
$this->addContentDispositionHeader();
$this->addHeader('Content-Length', $size);
return $data['content'];
}
/**
* Send 416 if we can't satisfy the requested ranges
*/
protected function sendRangeNotSatisfiable($filesize){
$this->setStatus(Http::STATUS_REQUEST_RANGE_NOT_SATISFIABLE);
$this->addHeader('Content-Range', 'bytes */' . $filesize); // Required in 416.
return '';
}
protected function addContentDispositionHeader(){
$encodedName = rawurlencode(basename($this->path));
$isIE = preg_match("/MSIE/", $this->request->server["HTTP_USER_AGENT"]);
if ($isIE){
$this->addHeader(
'Content-Disposition',
'attachment; filename="' . $encodedName . '"'
);
} else {
$this->addHeader(
'Content-Disposition',
'attachment; filename*=UTF-8\'\'' . $encodedName . '; filepath="' . $encodedName . '"'
);
}
}
}
Loading…
Cancel
Save