Permalink
Browse files

Implement our own accelerators (dl / up) using headers. Todo: recheck…

… generic StreamWrapper
  • Loading branch information...
1 parent e0d7b8e commit 67f291cadf78c67ba942311428c13a8b2014a15b @cdujeu cdujeu committed Jul 9, 2016
@@ -0,0 +1,73 @@
+<?php
+/*
+ * Copyright 2007-2016 Abstrium <contact (at) pydio.com>
+ * This file is part of Pydio.
+ *
+ * Pydio is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Pydio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Pydio. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * The latest code can be found at <https://pydio.com/>.
+ */
+namespace Pydio\Core\Http\Message;
+
+use Zend\Diactoros\UploadedFile;
+
+defined('AJXP_EXEC') or die('Access not allowed');
+
+/**
+ * Class ExternalUploadedFile
+ * @package Pydio\Core\Http\Message
+ */
+class ExternalUploadedFile extends UploadedFile
+{
+ const STATUS_REQUEST_OPTIONS = "request-options";
+ const STATUS_UPLOAD_FINISHED = "upload-finished";
+ const STATUS_UPLOAD_ERROR = "upload-error";
+
+ private $status;
+
+ /**
+ * ExternalUploadedFile constructor.
+ * @param string $status self::STATUS_REQUEST_OPTIONS, UPLOAD_FINISHED, UPLOAD_ERROR
+ * @param int $size
+ * @param int $clientFilename
+ */
+ public function __construct($status, $size, $clientFilename)
+ {
+ parent::__construct(
+ "fake-tmp-file",
+ $size,
+ $status === self::STATUS_UPLOAD_ERROR ? UPLOAD_ERR_NO_FILE : UPLOAD_ERR_OK,
+ $clientFilename,
+ null
+ );
+ $this->status = $status;
+ }
+
+ /**
+ * @return string One of the ExternalUploadedFile::STATUS_XXX constant value
+ */
+ public function getStatus(){
+ return $this->status;
+ }
+
+ /**
+ * Check if status has a valid value
+ * @param $status
+ * @return bool
+ */
+ public static function isValidStatus($status){
+ return in_array($status, [self::STATUS_REQUEST_OPTIONS, self::STATUS_UPLOAD_ERROR, self::STATUS_UPLOAD_FINISHED]);
+ }
+
+}
@@ -26,6 +26,7 @@
use Pydio\Core\Controller\HTMLWriter;
use Pydio\Core\Services\ConfService;
use Pydio\Core\Utils\ApplicationState;
+use Pydio\Core\Utils\FileHelper;
use Pydio\Core\Utils\Vars\StatHelper;
use Pydio\Core\Utils\TextEncoder;
use Pydio\Log\Core\Logger;
@@ -69,6 +70,9 @@ class FileReaderResponse extends AsyncResponseStream
/** @var callable */
private $postRead;
+ /** @var boolean */
+ private $unlinkAfterRead;
+
/**
* FileReaderResponse constructor.
* @param AJXP_Node|string $nodeOrFile
@@ -140,6 +144,13 @@ public function setPostReadCallback(callable $post){
}
/**
+ * Set a flag to trigger an unlink after reading the file.
+ */
+ public function setUnlinkAfterRead(){
+ $this->unlinkAfterRead = true;
+ }
+
+ /**
* Actually read the data to the output
* @throws \Exception
*/
@@ -178,8 +189,13 @@ public function readFile($node = null, $filePath = null, $data = null, $headerTy
}
$confGzip = ConfService::getGlobalConf("GZIP_COMPRESSION");
$confGzipLimit = ConfService::getGlobalConf("GZIP_LIMIT");
- $confUseXSendFile = ConfService::getGlobalConf("USE_XSENDFILE");
- $confUseXAccelRedirect = ConfService::getGlobalConf("USE_XACCELREDIRECT");
+ $confUseAccelerator = ConfService::getGlobalConf("USE_DOWNLOAD_ACCELERATOR");
+ if($this->unlinkAfterRead && $filePathOrData !== null && empty($confUseAccelerator)){
+ register_shutdown_function(function () use ($filePathOrData){
+ FileHelper::silentUnlink($filePathOrData);
+ });
+ }
+
$fakeReq = ServerRequestFactory::fromGlobals();
$serverParams = $fakeReq->getServerParams();
@@ -320,42 +336,9 @@ public function readFile($node = null, $filePath = null, $data = null, $headerTy
} else {
- if(($node !== null && !$node->wrapperIsRemote()) || $filePath !== null){
-
- if ($confUseXSendFile) {
- if($node != null) {
- $filePathOrData = $node->getRealFile();
- }
- $filePathOrData = str_replace("\\", "/", $filePathOrData);
- $server_name = $serverParams["SERVER_SOFTWARE"];
- $regex = '/^(lighttpd\/1.4).([0-9]{2}$|[0-9]{3}$|[0-9]{4}$)+/';
- if(preg_match($regex, $server_name))
- $header_sendfile = "X-LIGHTTPD-send-file";
- else
- $header_sendfile = "X-Sendfile";
-
-
- header($header_sendfile.": ".TextEncoder::toUTF8($filePathOrData));
- header("Content-type: application/octet-stream");
- header('Content-Disposition: attachment; filename="' . basename($filePathOrData) . '"');
- return;
- }
- if ($confUseXAccelRedirect && array_key_exists("X-Accel-Mapping", $serverParams)) {
- if($node !== null) {
- $filePathOrData = $node->getRealFile();
- }
- $filePathOrData = str_replace("\\", "/", $filePathOrData);
- $filePathOrData = TextEncoder::toUTF8($filePathOrData);
- $mapping = explode('=',$serverParams['X-Accel-Mapping']);
- $replacecount = 0;
- $accelfile = str_replace($mapping[0],$mapping[1],$filePathOrData,$replacecount);
- if ($replacecount == 1) {
- header("X-Accel-Redirect: $accelfile");
- header("Content-type: application/octet-stream");
- header('Content-Disposition: attachment; filename="' . basename($accelfile) . '"');
- } else {
- $this->logDebug("X-Accel-Redirect: Problem with X-Accel-Mapping for file $filePathOrData");
- }
+ if ( !empty($confUseAccelerator)){
+ $requestSent = $this->sendToAccelerator($confUseAccelerator, ($node !== null ? $node : $filePath), $serverParams);
+ if($requestSent){
return;
}
}
@@ -400,5 +383,89 @@ public function readFile($node = null, $filePath = null, $data = null, $headerTy
}
}
+ /**
+ * @param string $accelConfiguration
+ * @param string|AJXP_Node $localPathOrNode
+ * @param array $serverParams
+ * @return bool Wether headers were sent and we should interrupt DL now or not.
+ */
+ protected function sendToAccelerator($accelConfiguration, $localPathOrNode, $serverParams){
+
+ $remoteNode = false;
+ if($localPathOrNode instanceof AJXP_Node) {
+ $filePathOrData = $localPathOrNode->getRealFile();
+ $remoteNode = $localPathOrNode->wrapperIsRemote();
+ }else{
+ $filePathOrData = $localPathOrNode;
+ }
+
+ // TRY XSendFile for local FS nodes or local file
+ if (!$remoteNode && $accelConfiguration === "xsendfile") {
+
+ $filePathOrData = str_replace("\\", "/", $filePathOrData);
+ $server_name = $serverParams["SERVER_SOFTWARE"];
+ $regex = '/^(lighttpd\/1.4).([0-9]{2}$|[0-9]{3}$|[0-9]{4}$)+/';
+ if(preg_match($regex, $server_name))
+ $header_sendfile = "X-LIGHTTPD-send-file";
+ else
+ $header_sendfile = "X-Sendfile";
+
+
+ header($header_sendfile.": ".TextEncoder::toUTF8($filePathOrData));
+ header("Content-type: application/octet-stream");
+ header('Content-Disposition: attachment; filename="' . basename($filePathOrData) . '"');
+ return true;
+
+ }
+
+ // TRY XAccelRedirect for local FS nodes or local file
+ if (!$remoteNode && $accelConfiguration === "xaccelredirect" && array_key_exists("HTTP_X_ACCEL_MAPPING", $serverParams)) {
+
+ $filePathOrData = str_replace("\\", "/", $filePathOrData);
+ $filePathOrData = TextEncoder::toUTF8($filePathOrData);
+ $mapping = explode('=',$serverParams['X-Accel-Mapping']);
+ $replacecount = 0;
+ $accelfile = str_replace($mapping[0],$mapping[1],$filePathOrData,$replacecount);
+ if ($replacecount == 1) {
+ header("X-Accel-Redirect: $accelfile");
+ header("Content-type: application/octet-stream");
+ header('Content-Disposition: attachment; filename="' . basename($accelfile) . '"');
+ return true;
+ } else {
+ $this->logDebug("X-Accel-Redirect: Problem with X-Accel-Mapping for file $filePathOrData");
+ return false;
+ }
+
+ }
+
+ // Pydio Agent acceleration - We make sure that request was really proxied by Agent, by checking a specific header.
+ if($accelConfiguration === "pydio" && array_key_exists("HTTP_X_PYDIO_DOWNLOAD_SUPPORTED", $serverParams)) {
+
+ if ($localPathOrNode instanceof AJXP_Node) {
+ $options = MetaStreamWrapper::getResolvedOptionsForNode($localPathOrNode);
+ if($options["TYPE"] === "php"){
+ // Not implemented
+ return false;
+ }
+ $path = $localPathOrNode->getPath();
+ }else{
+ $options = ["TYPE" => "local"];
+ $path = $localPathOrNode;
+ }
+ $data = [
+ "OPTIONS" => $options,
+ "PATH" => $path
+ ];
+ if($this->unlinkAfterRead){
+ $data["UNLINK_AFTER_READ"] = true;
+ }
+ header("X-Pydio-Download-Redirect: ".json_encode($data));
+ header("Content-type: application/octet-stream");
+ header('Content-Disposition: attachment; filename="' . basename($path) . '"');
+ return true;
+ }
+
+ return false;
+ }
}
Oops, something went wrong.

0 comments on commit 67f291c

Please sign in to comment.