Merge "Truncate SHA-1 indexes"
[lhc/web/wiklou.git] / includes / filebackend / SwiftFileBackend.php
index 7f91ae3..185a557 100644 (file)
@@ -81,7 +81,8 @@ class SwiftFileBackend extends FileBackendStore {
         *                             - levels : the number of hash levels (and digits)
         *                             - repeat : hash subdirectories are prefixed with all the
         *                                        parent hash directory names (e.g. "a/ab/abc")
-        *   - cacheAuthInfo      : Whether to cache authentication tokens in APC/XCache.
+        *   - cacheAuthInfo      : Whether to cache authentication tokens in APC, XCache, ect.
+        *                          If those are not available, then the main cache will be used.
         *                          This is probably insecure in shared hosting environments.
         */
        public function __construct( array $config ) {
@@ -121,9 +122,13 @@ class SwiftFileBackend extends FileBackendStore {
                $this->connContainerCache = new ProcessCacheLRU( 300 );
                // Cache auth token information to avoid RTTs
                if ( !empty( $config['cacheAuthInfo'] ) ) {
-                       try { // look for APC, XCache, WinCache, ect...
-                               $this->srvCache = ObjectCache::newAccelerator( array() );
-                       } catch ( Exception $e ) {}
+                       if ( php_sapi_name() === 'cli' ) {
+                               $this->srvCache = wfGetMainCache(); // preferrably memcached
+                       } else {
+                               try { // look for APC, XCache, WinCache, ect...
+                                       $this->srvCache = ObjectCache::newAccelerator( array() );
+                               } catch ( Exception $e ) {}
+                       }
                }
                $this->srvCache = $this->srvCache ? $this->srvCache : new EmptyBagOStuff();
        }
@@ -162,6 +167,24 @@ class SwiftFileBackend extends FileBackendStore {
                return false;
        }
 
+       /**
+        * @param $disposition string Content-Disposition header value
+        * @return string Truncated Content-Disposition header value to meet Swift limits
+        */
+       protected function truncDisp( $disposition ) {
+               $res = '';
+               foreach ( explode( ';', $disposition ) as $part ) {
+                       $part = trim( $part );
+                       $new  = ( $res === '' ) ? $part : "{$res};{$part}";
+                       if ( strlen( $new ) <= 255 ) {
+                               $res = $new;
+                       } else {
+                               break; // too long; sigh
+                       }
+               }
+               return $res;
+       }
+
        /**
         * @see FileBackendStore::doCreateInternal()
         * @return Status
@@ -212,7 +235,7 @@ class SwiftFileBackend extends FileBackendStore {
                        }
                        // Set the Content-Disposition header if requested
                        if ( isset( $params['disposition'] ) ) {
-                               $obj->headers['Content-Disposition'] = $params['disposition'];
+                               $obj->headers['Content-Disposition'] = $this->truncDisp( $params['disposition'] );
                        }
                        if ( !empty( $params['async'] ) ) { // deferred
                                $op = $obj->write_async( $params['content'] );
@@ -302,7 +325,7 @@ class SwiftFileBackend extends FileBackendStore {
                        }
                        // Set the Content-Disposition header if requested
                        if ( isset( $params['disposition'] ) ) {
-                               $obj->headers['Content-Disposition'] = $params['disposition'];
+                               $obj->headers['Content-Disposition'] = $this->truncDisp( $params['disposition'] );
                        }
                        if ( !empty( $params['async'] ) ) { // deferred
                                wfSuppressWarnings();
@@ -392,7 +415,7 @@ class SwiftFileBackend extends FileBackendStore {
                        $dstObj = new CF_Object( $dContObj, $dstRel, false, false ); // skip HEAD
                        $hdrs = array(); // source file headers to override with new values
                        if ( isset( $params['disposition'] ) ) {
-                               $hdrs['Content-Disposition'] = $params['disposition'];
+                               $hdrs['Content-Disposition'] = $this->truncDisp( $params['disposition'] );
                        }
                        if ( !empty( $params['async'] ) ) { // deferred
                                $op = $sContObj->copy_object_to_async( $srcRel, $dContObj, $dstRel, null, $hdrs );
@@ -471,7 +494,7 @@ class SwiftFileBackend extends FileBackendStore {
                        $dstObj = new CF_Object( $dContObj, $dstRel, false, false ); // skip HEAD
                        $hdrs = array(); // source file headers to override with new values
                        if ( isset( $params['disposition'] ) ) {
-                               $hdrs['Content-Disposition'] = $params['disposition'];
+                               $hdrs['Content-Disposition'] = $this->truncDisp( $params['disposition'] );
                        }
                        if ( !empty( $params['async'] ) ) { // deferred
                                $op = $sContObj->move_object_to_async( $srcRel, $dContObj, $dstRel, null, $hdrs );
@@ -766,8 +789,7 @@ class SwiftFileBackend extends FileBackendStore {
                $status = Status::newGood();
                $scopeLockS = $this->getScopedFileLocks( array( $path ), LockManager::LOCK_UW, $status );
                if ( $status->isOK() ) {
-                       # Do not stat the file in getLocalCopy() to avoid infinite loops
-                       $tmpFile = $this->getLocalCopy( array( 'src' => $path, 'latest' => 1, 'nostat' => 1 ) );
+                       $tmpFile = $this->getLocalCopy( array( 'src' => $path, 'latest' => 1 ) );
                        if ( $tmpFile ) {
                                $hash = $tmpFile->getSha1Base36();
                                if ( $hash !== false ) {
@@ -785,7 +807,7 @@ class SwiftFileBackend extends FileBackendStore {
 
        /**
         * @see FileBackend::getFileContents()
-        * @return bool|null|string
+        * @return bool|string
         */
        public function getFileContents( array $params ) {
                list( $srcCont, $srcRel ) = $this->resolveStoragePathReal( $params['src'] );
@@ -793,16 +815,13 @@ class SwiftFileBackend extends FileBackendStore {
                        return false; // invalid storage path
                }
 
-               if ( !$this->fileExists( $params ) ) {
-                       return null;
-               }
-
                $data = false;
                try {
                        $sContObj = $this->getContainer( $srcCont );
                        $obj = new CF_Object( $sContObj, $srcRel, false, false ); // skip HEAD
                        $data = $obj->read( $this->headersFromParams( $params ) );
                } catch ( NoSuchContainerException $e ) {
+               } catch ( NoSuchObjectException $e ) {
                } catch ( CloudFilesException $e ) { // some other exception?
                        $this->handleException( $e, null, __METHOD__, $params );
                }
@@ -1005,6 +1024,8 @@ class SwiftFileBackend extends FileBackendStore {
                        $output = fopen( 'php://output', 'wb' );
                        $obj = new CF_Object( $cont, $srcRel, false, false ); // skip HEAD
                        $obj->stream( $output, $this->headersFromParams( $params ) );
+               } catch ( NoSuchObjectException $e ) {
+                       $status->fatal( 'backend-fail-stream', $params['src'] );
                } catch ( CloudFilesException $e ) { // some other exception?
                        $this->handleException( $e, $status, __METHOD__, $params );
                }
@@ -1023,7 +1044,7 @@ class SwiftFileBackend extends FileBackendStore {
                }
 
                // Blindly create a tmp file and stream to it, catching any exception if the file does
-               // not exist. Also, doing a stat here will cause infinite loops when filling metadata.
+               // not exist. Also, doing a stat here will cause infinite loops in addMissingMetadata().
                $tmpFile = null;
                try {
                        $sContObj = $this->getContainer( $srcCont );