forked from phacility/phabricator
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathPhabricatorFileTransformController.php
141 lines (113 loc) · 3.95 KB
/
PhabricatorFileTransformController.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
<?php
final class PhabricatorFileTransformController
extends PhabricatorFileController {
public function shouldRequireLogin() {
return false;
}
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
// NOTE: This is a public/CDN endpoint, and permission to see files is
// controlled by knowing the secret key, not by authentication.
$is_regenerate = $request->getBool('regenerate');
$source_phid = $request->getURIData('phid');
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($source_phid))
->executeOne();
if (!$file) {
return new Aphront404Response();
}
$secret_key = $request->getURIData('key');
if (!$file->validateSecretKey($secret_key)) {
return new Aphront403Response();
}
$transform = $request->getURIData('transform');
$xform = $this->loadTransform($source_phid, $transform);
if ($xform) {
if ($is_regenerate) {
$this->destroyTransform($xform);
} else {
return $this->buildTransformedFileResponse($xform);
}
}
$xforms = PhabricatorFileTransform::getAllTransforms();
if (!isset($xforms[$transform])) {
return new Aphront404Response();
}
$xform = $xforms[$transform];
// We're essentially just building a cache here and don't need CSRF
// protection.
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
$xformed_file = null;
if ($xform->canApplyTransform($file)) {
try {
$xformed_file = $xforms[$transform]->applyTransform($file);
} catch (Exception $ex) {
// In normal transform mode, we ignore failures and generate a
// default transform below. If we're explicitly regenerating the
// thumbnail, rethrow the exception.
if ($is_regenerate) {
throw $ex;
}
}
}
if (!$xformed_file) {
$xformed_file = $xform->getDefaultTransform($file);
}
if (!$xformed_file) {
return new Aphront400Response();
}
$xform = id(new PhabricatorTransformedFile())
->setOriginalPHID($source_phid)
->setTransform($transform)
->setTransformedPHID($xformed_file->getPHID());
try {
$xform->save();
} catch (AphrontDuplicateKeyQueryException $ex) {
// If we collide when saving, we've raced another endpoint which was
// transforming the same file. Just throw our work away and use that
// transform instead.
$this->destroyTransform($xform);
$xform = $this->loadTransform($source_phid, $transform);
if (!$xform) {
return new Aphront404Response();
}
}
return $this->buildTransformedFileResponse($xform);
}
private function buildTransformedFileResponse(
PhabricatorTransformedFile $xform) {
$file = id(new PhabricatorFileQuery())
->setViewer(PhabricatorUser::getOmnipotentUser())
->withPHIDs(array($xform->getTransformedPHID()))
->executeOne();
if (!$file) {
return new Aphront404Response();
}
// TODO: We could just delegate to the file view controller instead,
// which would save the client a roundtrip, but is slightly more complex.
return $file->getRedirectResponse();
}
private function destroyTransform(PhabricatorTransformedFile $xform) {
$engine = new PhabricatorDestructionEngine();
$file = id(new PhabricatorFileQuery())
->setViewer($engine->getViewer())
->withPHIDs(array($xform->getTransformedPHID()))
->executeOne();
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
if (!$file) {
if ($xform->getID()) {
$xform->delete();
}
} else {
$engine->destroyObject($file);
}
unset($unguarded);
}
private function loadTransform($source_phid, $transform) {
return id(new PhabricatorTransformedFile())->loadOneWhere(
'originalPHID = %s AND transform = %s',
$source_phid,
$transform);
}
}