@@ -11,21 +11,12 @@ public function handleRequest(AphrontRequest $request) {
1111 $ viewer = $ request ->getViewer ();
1212 $ img_uri = $ request ->getStr ('uri ' );
1313
14- // Validate the URI before doing anything
15- PhabricatorEnv::requireValidRemoteURIForLink ($ img_uri );
14+ // Validate the URI before doing anything, including DNS resolution and
15+ // outbound blacklist check, to fail fast before consuming rate limit tokens.
16+ PhabricatorEnv::requireValidRemoteURIForFetch (
17+ $ img_uri ,
18+ array ('http ' , 'https ' ));
1619 $ uri = new PhutilURI ($ img_uri );
17- $ proto = $ uri ->getProtocol ();
18-
19- $ allowed_protocols = array (
20- 'http ' ,
21- 'https ' ,
22- );
23- if (!in_array ($ proto , $ allowed_protocols )) {
24- throw new Exception (
25- pht (
26- 'The provided image URI must use one of these protocols: %s. ' ,
27- implode (', ' , $ allowed_protocols )));
28- }
2920
3021 // Check if we already have the specified image URI downloaded
3122 $ cached_request = id (new PhabricatorFileExternalRequest ())->loadOneWhere (
@@ -45,10 +36,11 @@ public function handleRequest(AphrontRequest $request) {
4536 $ unguarded = AphrontWriteGuard::beginScopedUnguardedWrites ();
4637 $ save_request = false ;
4738 try {
48- // Rate limit outbound fetches to make this mechanism less useful for
49- // scanning networks and ports.
39+ // Rate limit outbound fetches by remote IP to make this mechanism less
40+ // useful for scanning networks and ports. Using IP (not PHID) ensures
41+ // anonymous users are not all collapsed into a single actor.
5042 PhabricatorSystemActionEngine::willTakeAction (
51- array ($ viewer -> getPHID ( )),
43+ array (PhabricatorSystemActionEngine:: newActorFromRequest ( $ request )),
5244 new PhabricatorFilesOutboundRequestAction (),
5345 1 );
5446
@@ -64,13 +56,14 @@ public function handleRequest(AphrontRequest $request) {
6456 $ engine = new PhabricatorDestructionEngine ();
6557 $ engine ->destroyObject ($ file );
6658 $ file = null ;
59+ phlog (pht (
60+ 'Image proxy rejected "%s": not a valid image (MIME type: "%s"). ' ,
61+ $ uri ,
62+ $ mime_type ));
6763 throw new Exception (
6864 pht (
69- 'The URI "%s" does not correspond to a valid image file (got ' .
70- 'a file with MIME type "%s"). You must specify the URI of a ' .
71- 'valid image file. ' ,
72- $ uri ,
73- $ mime_type ));
65+ 'The URI does not correspond to a valid image file. ' .
66+ 'You must specify the URI of a valid image file. ' ));
7467 }
7568
7669 $ file ->save ();
@@ -119,11 +112,12 @@ public function handleRequest(AphrontRequest $request) {
119112 private function getExternalResponse (
120113 PhabricatorFileExternalRequest $ request ) {
121114 if (!$ request ->getIsSuccessful ()) {
115+ phlog (pht (
116+ 'Image proxy failed for "%s": %s ' ,
117+ $ request ->getURI (),
118+ $ request ->getResponseMessage ()));
122119 throw new Exception (
123- pht (
124- 'Request to "%s" failed: %s ' ,
125- $ request ->getURI (),
126- $ request ->getResponseMessage ()));
120+ pht ('Unable to load the requested image. ' ));
127121 }
128122
129123 $ file = id (new PhabricatorFileQuery ())
0 commit comments