Implement downloadresponse via appframework
parent
4180d66555
commit
7416b8b5d6
@ -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…
Reference in New Issue