DownloadResponse   A
last analyzed

Complexity

Total Complexity 16

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 0
Metric Value
wmc 16
c 2
b 1
f 0
lcom 1
cbo 1
dl 0
loc 107
ccs 0
cts 77
cp 0
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 11 2
C render() 0 58 11
A sendRangeNotSatisfiable() 0 5 1
A addContentDispositionHeader() 0 15 2
1
<?php
2
/**
3
 * ownCloud - Documents App
4
 *
5
 * @author Victor Dubiniuk
6
 * @copyright 2014 Victor Dubiniuk [email protected]
7
 *
8
 * This file is licensed under the Affero General Public License version 3 or
9
 * later.
10
 */
11
12
namespace OCA\Documents;
13
14
use OC\Files\Filesystem;
15
use \OCP\AppFramework\Http;
16
use \OCP\IRequest;
17
use \OC\Files\View;
18
19
class DownloadResponse extends \OCP\AppFramework\Http\Response {
20
	private $request;
21
	private $view;
22
	private $path;
23
	
24
	/**
25
	 * @param IRequest $request
26
	 * @param string $user
27
	 * @param string $path
28
	 */
29
	public function __construct(IRequest $request, $user, $path) {
30
		$this->request = $request;
31
		$this->user = $user;
32
		$this->path = $path;
33
34
		Filesystem::initMountPoints($user);
35
		$this->view = new View('/' . $user);
36
		if (!$this->view->file_exists($path)){
37
			$this->setStatus(Http::STATUS_NOT_FOUND);
38
		}
39
	}
40
	
41
	public function render(){
42
		if ($this->getStatus() === Http::STATUS_NOT_FOUND){
43
			return '';
44
		}
45
		$info = $this->view->getFileInfo($this->path);
46
		$this->ETag = $info['etag'];
47
		
48
		$content = $this->view->file_get_contents($this->path);
49
		$data = \OCA\Documents\Filter::read($content, $info['mimetype']);
50
		$size = strlen($data['content']);
51
		
52
		
53
		if (isset($this->request->server['HTTP_RANGE']) && !is_null($this->request->server['HTTP_RANGE'])){
54
			$isValidRange = preg_match('/^bytes=\d*-\d*(,\d*-\d*)*$/', $this->request->server['HTTP_RANGE']);
55
			if (!$isValidRange){
56
				return $this->sendRangeNotSatisfiable($size);
57
			}
58
			
59
			$ranges = explode(',', substr($this->request->server['HTTP_RANGE'], 6));
60
			foreach ($ranges as $range){
61
				$parts = explode('-', $range);
62
63
				if ($parts[0]==='' && $parts[1]=='') {
64
					$this->sendNotSatisfiable($size);
65
				}
66
				if ($parts[0]==='') {
67
					$start = $size - $parts[1];
68
					$end = $size - 1;
69
				} else {
70
					$start = $parts[0];
71
					$end = ($parts[1]==='') ? $size - 1 : $parts[1];
72
				}
73
74
				if ($start > $end){
75
					$this->sendNotSatisfiable($size);
76
				}
77
78
				$buffer = substr($data['content'], $start,  $end - $start);
79
				$md5Sum = md5($buffer);
80
81
				// send the headers and data 
82
				$this->addHeader('Content-Length',  $end - $start);
83
				$this->addHeader('Content-md5', $md5Sum);
84
				$this->addHeader('Accept-Ranges', 'bytes');
85
				$this->addHeader('Content-Range', 'bytes ' . $start . '-' . ($end) . '/' . $size);
86
				$this->addHeader('Connection', 'close');
87
				$this->addHeader('Content-Type', $data['mimetype']);
88
				$this->addContentDispositionHeader();
89
				return $buffer;
90
			}
91
		}
92
		
93
		$this->addHeader('Content-Type', $data['mimetype']);
94
		$this->addContentDispositionHeader();
95
		$this->addHeader('Content-Length',  $size);
96
97
		return $data['content'];
98
	}
99
	
100
	/**
101
	 * Send 416 if we can't satisfy the requested ranges
102
	 * @param integer $filesize
103
	 */
104
	protected function sendRangeNotSatisfiable($filesize){
105
		$this->setStatus(Http::STATUS_REQUEST_RANGE_NOT_SATISFIABLE);
106
		$this->addHeader('Content-Range', 'bytes */' . $filesize); // Required in 416.
107
		return '';
108
	}
109
	
110
	protected function addContentDispositionHeader(){
111
		$encodedName = rawurlencode(basename($this->path));
112
		$isIE = preg_match("/MSIE/", $this->request->server["HTTP_USER_AGENT"]);
113
		if ($isIE){
114
			$this->addHeader(
115
					'Content-Disposition',
116
					'attachment; filename="' . $encodedName . '"'
117
			);
118
		} else {
119
			$this->addHeader(
120
					'Content-Disposition',
121
					'attachment; filename*=UTF-8\'\'' . $encodedName . '; filepath="' . $encodedName . '"'
122
			);
123
		}
124
	}
125
}
126