Passed
Push — master ( bc1f01...8cd5d8 )
by Pauli
03:17 queued 15s
created

RelayStreamResponse::__construct()   B

Complexity

Conditions 8
Paths 68

Size

Total Lines 39
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 23
c 1
b 0
f 0
nc 68
nop 1
dl 0
loc 39
rs 8.4444
1
<?php declare(strict_types=1);
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2024
11
 */
12
13
namespace OCA\Music\Http;
14
15
use OCP\AppFramework\Http\ICallbackResponse;
16
use OCP\AppFramework\Http\IOutput;
17
use OCP\AppFramework\Http\Response;
18
use OCP\AppFramework\Http;
19
20
use OCA\Music\Utility\HttpUtil;
21
22
/**
23
 * Response which relays a radio stream or similar from an original source URL
24
 */
25
class RelayStreamResponse extends Response implements ICallbackResponse {
26
	private ?string $url;
27
	/** @var resource $context */
28
	private $context;
29
30
	public function __construct(string $url) {
31
		$this->url = $url;
32
33
		$reqHeaders = [];
34
		if (isset($_SERVER['HTTP_ACCEPT'])) {
35
			$reqHeaders['Accept'] = $_SERVER['HTTP_ACCEPT'];
36
		}
37
		if (isset($_SERVER['HTTP_RANGE'])) {
38
			$reqHeaders['Range'] = $_SERVER['HTTP_RANGE'];
39
		}
40
41
		$this->context = HttpUtil::createContext(null, $reqHeaders);
42
43
		// Get headers from the source and relay the important ones to our client
44
		$sourceHeaders = HttpUtil::getUrlHeaders($url, $this->context);
45
	
46
		if ($sourceHeaders !== null) {
47
			// According to RFC 2616, HTTP headers are case-insensitive but we need predictable keys
48
			$sourceHeaders = \array_change_key_case($sourceHeaders, CASE_LOWER);
49
50
			if (isset($sourceHeaders['content-type'])) {
51
				$this->addHeader('Content-Type', $sourceHeaders['content-type']);
52
			}
53
			if (isset($sourceHeaders['content-length'])) {
54
				$this->addHeader('Content-Length', $sourceHeaders['content-length']);
55
			}
56
			if (isset($sourceHeaders['accept-ranges'])) {
57
				$this->addHeader('Accept-Ranges', $sourceHeaders['accept-ranges']);
58
			}
59
			if (isset($sourceHeaders['content-range'])) {
60
				$this->addHeader('Content-Range', $sourceHeaders['content-range']);
61
			}
62
63
			$this->setStatus($sourceHeaders['status_code']);
64
		}
65
		else {
66
			$this->addHeader('Content-Length', '0');
67
			$this->setStatus(Http::STATUS_FORBIDDEN);
68
			$this->url = null;
69
		}
70
	}
71
72
	public function callback(IOutput $output) {
73
		if ($this->url !== null) {
74
			$inStream = \fopen($this->url, 'rb', false, $this->context);
75
			$outStream = \fopen('php://output', 'wb');
76
77
			$bytesCopied = \stream_copy_to_stream($inStream, $outStream);
0 ignored issues
show
Unused Code introduced by
The assignment to $bytesCopied is dead and can be removed.
Loading history...
78
			\fclose($outStream);
79
			\fclose($inStream);
80
		}
81
	}
82
}
83