Update formatting of includes/upload/
Change-Id: I8cf59cd3bb6dd8de2ed6509b7bc2ef9ff7c5caf1
This commit is contained in:
parent
79fa6f546a
commit
69a2ecfe3e
6 changed files with 176 additions and 49 deletions
|
|
@ -120,6 +120,7 @@ abstract class UploadBase {
|
|||
return $permission;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -167,6 +168,7 @@ abstract class UploadBase {
|
|||
$handler = new $className;
|
||||
|
||||
$handler->initializeFromRequest( $request );
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
|
|
@ -179,7 +181,8 @@ abstract class UploadBase {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function __construct() {}
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the upload type. Should be overridden by child classes
|
||||
|
|
@ -267,6 +270,7 @@ abstract class UploadBase {
|
|||
$path = $srcPath;
|
||||
}
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
|
@ -282,6 +286,7 @@ abstract class UploadBase {
|
|||
*/
|
||||
if ( $this->isEmptyFile() ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'status' => self::EMPTY_FILE );
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +296,7 @@ abstract class UploadBase {
|
|||
$maxSize = self::getMaxUploadSize( $this->getSourceType() );
|
||||
if ( $this->mFileSize > $maxSize ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array(
|
||||
'status' => self::FILE_TOO_LARGE,
|
||||
'max' => $maxSize,
|
||||
|
|
@ -305,6 +311,7 @@ abstract class UploadBase {
|
|||
$verification = $this->verifyFile();
|
||||
if ( $verification !== true ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array(
|
||||
'status' => self::VERIFICATION_ERROR,
|
||||
'details' => $verification
|
||||
|
|
@ -317,6 +324,7 @@ abstract class UploadBase {
|
|||
$result = $this->validateName();
|
||||
if ( $result !== true ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
|
@ -325,10 +333,12 @@ abstract class UploadBase {
|
|||
array( $this->mDestName, $this->mTempPath, &$error ) )
|
||||
) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'status' => self::HOOK_ABORTED, 'error' => $error );
|
||||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'status' => self::OK );
|
||||
}
|
||||
|
||||
|
|
@ -351,6 +361,7 @@ abstract class UploadBase {
|
|||
$result['blacklistedExt'] = $this->mBlackListedExtensions;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
$this->mDestName = $this->getLocalFile()->getName();
|
||||
|
|
@ -374,6 +385,7 @@ abstract class UploadBase {
|
|||
global $wgMimeTypeBlacklist;
|
||||
if ( $this->checkFileExtension( $mime, $wgMimeTypeBlacklist ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'filetype-badmime', $mime );
|
||||
}
|
||||
|
||||
|
|
@ -388,12 +400,14 @@ abstract class UploadBase {
|
|||
foreach ( $ieTypes as $ieType ) {
|
||||
if ( $this->checkFileExtension( $ieType, $wgMimeTypeBlacklist ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'filetype-bad-ie-mime', $ieType );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -409,6 +423,7 @@ abstract class UploadBase {
|
|||
$status = $this->verifyPartialFile();
|
||||
if ( $status !== true ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
|
@ -419,6 +434,7 @@ abstract class UploadBase {
|
|||
# XXX: Missing extension will be caught by validateName() via getTitle()
|
||||
if ( $this->mFinalExtension != '' && !$this->verifyExtension( $mime, $this->mFinalExtension ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'filetype-mime-mismatch', $this->mFinalExtension, $mime );
|
||||
}
|
||||
}
|
||||
|
|
@ -429,6 +445,7 @@ abstract class UploadBase {
|
|||
if ( !$handlerStatus->isOK() ) {
|
||||
$errors = $handlerStatus->getErrorsArray();
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return reset( $errors );
|
||||
}
|
||||
}
|
||||
|
|
@ -436,11 +453,13 @@ abstract class UploadBase {
|
|||
wfRunHooks( 'UploadVerifyFile', array( $this, $mime, &$status ) );
|
||||
if ( $status !== true ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
wfDebug( __METHOD__ . ": all clear; passing.\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -466,6 +485,7 @@ abstract class UploadBase {
|
|||
$status = $this->verifyMimeType( $mime );
|
||||
if ( $status !== true ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
|
@ -473,12 +493,14 @@ abstract class UploadBase {
|
|||
if ( !$wgDisableUploadScriptChecks ) {
|
||||
if ( self::detectScript( $this->mTempPath, $mime, $this->mFinalExtension ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'uploadscripted' );
|
||||
}
|
||||
if ( $this->mFinalExtension == 'svg' || $mime == 'image/svg+xml' ) {
|
||||
$svgStatus = $this->detectScriptInSvg( $this->mTempPath );
|
||||
if ( $svgStatus !== false ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $svgStatus;
|
||||
}
|
||||
}
|
||||
|
|
@ -495,11 +517,13 @@ abstract class UploadBase {
|
|||
$error = reset( $errors );
|
||||
if ( $error[0] !== 'zip-wrong-format' ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $error;
|
||||
}
|
||||
}
|
||||
if ( $this->mJavaDetected ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'uploadjava' );
|
||||
}
|
||||
}
|
||||
|
|
@ -508,10 +532,12 @@ abstract class UploadBase {
|
|||
$virus = $this->detectVirus( $this->mTempPath );
|
||||
if ( $virus ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return array( 'uploadvirus', $virus );
|
||||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -581,6 +607,7 @@ abstract class UploadBase {
|
|||
if ( $permErrors || $permErrorsUpload || $permErrorsCreate ) {
|
||||
$permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsUpload, $permErrors ) );
|
||||
$permErrors = array_merge( $permErrors, wfArrayDiff2( $permErrorsCreate, $permErrors ) );
|
||||
|
||||
return $permErrors;
|
||||
}
|
||||
|
||||
|
|
@ -670,6 +697,7 @@ abstract class UploadBase {
|
|||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $warnings;
|
||||
}
|
||||
|
||||
|
|
@ -705,6 +733,7 @@ abstract class UploadBase {
|
|||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
|
@ -733,6 +762,7 @@ abstract class UploadBase {
|
|||
if ( strlen( $this->mFilteredName ) > 240 ) {
|
||||
$this->mTitleError = self::FILENAME_TOO_LONG;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
|
|
@ -747,6 +777,7 @@ abstract class UploadBase {
|
|||
if ( is_null( $nt ) ) {
|
||||
$this->mTitleError = self::ILLEGAL_FILENAME;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
$this->mFilteredName = $nt->getDBkey();
|
||||
|
|
@ -789,13 +820,16 @@ abstract class UploadBase {
|
|||
if ( $this->mFinalExtension == '' ) {
|
||||
$this->mTitleError = self::FILETYPE_MISSING;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
} elseif ( $blackListedExtensions ||
|
||||
( $wgCheckFileExtensions && $wgStrictFileExtensions &&
|
||||
!$this->checkFileExtension( $this->mFinalExtension, $wgFileExtensions ) ) ) {
|
||||
( $wgCheckFileExtensions && $wgStrictFileExtensions &&
|
||||
!$this->checkFileExtension( $this->mFinalExtension, $wgFileExtensions ) )
|
||||
) {
|
||||
$this->mBlackListedExtensions = $blackListedExtensions;
|
||||
$this->mTitleError = self::FILETYPE_BADTYPE;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
|
|
@ -803,6 +837,7 @@ abstract class UploadBase {
|
|||
if ( wfIsWindows() && !preg_match( '/^[\x0-\x7f]*$/', $nt->getText() ) ) {
|
||||
$this->mTitleError = self::WINDOWS_NONASCII_FILENAME;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
|
|
@ -817,10 +852,12 @@ abstract class UploadBase {
|
|||
if ( strlen( $partname ) < 1 ) {
|
||||
$this->mTitleError = self::MIN_LENGTH_PARTNAME;
|
||||
$this->mTitle = null;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
$this->mTitle = $nt;
|
||||
|
||||
return $this->mTitle;
|
||||
}
|
||||
|
||||
|
|
@ -834,6 +871,7 @@ abstract class UploadBase {
|
|||
$nt = $this->getTitle();
|
||||
$this->mLocalFile = is_null( $nt ) ? null : wfLocalFile( $nt );
|
||||
}
|
||||
|
||||
return $this->mLocalFile;
|
||||
}
|
||||
|
||||
|
|
@ -858,6 +896,7 @@ abstract class UploadBase {
|
|||
$this->mLocalFile = $file;
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
|
|
@ -906,6 +945,7 @@ abstract class UploadBase {
|
|||
public static function splitExtensions( $filename ) {
|
||||
$bits = explode( '.', $filename );
|
||||
$basename = array_shift( $bits );
|
||||
|
||||
return array( $basename, $bits );
|
||||
}
|
||||
|
||||
|
|
@ -947,10 +987,12 @@ abstract class UploadBase {
|
|||
if ( !$magic->isRecognizableExtension( $extension ) ) {
|
||||
wfDebug( __METHOD__ . ": passing file with unknown detected mime type; " .
|
||||
"unrecognized extension '$extension', can't verify\n" );
|
||||
|
||||
return true;
|
||||
} else {
|
||||
wfDebug( __METHOD__ . ": rejecting file with unknown detected mime type; " .
|
||||
"recognized extension '$extension', so probably invalid file\n" );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -960,9 +1002,11 @@ abstract class UploadBase {
|
|||
if ( $match === null ) {
|
||||
if ( $magic->getTypesForExtension( $extension ) !== null ) {
|
||||
wfDebug( __METHOD__ . ": No extension known for $mime, but we know a mime for $extension\n" );
|
||||
|
||||
return false;
|
||||
} else {
|
||||
wfDebug( __METHOD__ . ": no file extension known for mime type $mime, passing file\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
} elseif ( $match === true ) {
|
||||
|
|
@ -970,9 +1014,9 @@ abstract class UploadBase {
|
|||
|
||||
#TODO: if it's a bitmap, make sure PHP or ImageMagic resp. can handle it!
|
||||
return true;
|
||||
|
||||
} else {
|
||||
wfDebug( __METHOD__ . ": mime type $mime mismatches file extension $extension, rejecting file\n" );
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1007,6 +1051,7 @@ abstract class UploadBase {
|
|||
|
||||
if ( !$chunk ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1031,6 +1076,7 @@ abstract class UploadBase {
|
|||
# check for HTML doctype
|
||||
if ( preg_match( "/<!DOCTYPE *X?HTML/i", $chunk ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1039,6 +1085,7 @@ abstract class UploadBase {
|
|||
if ( $extension == 'svg' || strpos( $mime, 'image/svg' ) === 0 ) {
|
||||
if ( self::checkXMLEncodingMissmatch( $file ) ) {
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1062,7 +1109,7 @@ abstract class UploadBase {
|
|||
'<a href',
|
||||
'<body',
|
||||
'<head',
|
||||
'<html', #also in safari
|
||||
'<html', #also in safari
|
||||
'<img',
|
||||
'<pre',
|
||||
'<script', #also in safari
|
||||
|
|
@ -1077,6 +1124,7 @@ abstract class UploadBase {
|
|||
if ( false !== strpos( $chunk, $tag ) ) {
|
||||
wfDebug( __METHOD__ . ": found something that may make it be mistaken for html: $tag\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1092,6 +1140,7 @@ abstract class UploadBase {
|
|||
if ( preg_match( '!type\s*=\s*[\'"]?\s*(?:\w*/)?(?:ecma|java)!sim', $chunk ) ) {
|
||||
wfDebug( __METHOD__ . ": found script types\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1099,6 +1148,7 @@ abstract class UploadBase {
|
|||
if ( preg_match( '!(?:href|src|data)\s*=\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) {
|
||||
wfDebug( __METHOD__ . ": found html-style script urls\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1106,11 +1156,13 @@ abstract class UploadBase {
|
|||
if ( preg_match( '!url\s*\(\s*[\'"]?\s*(?:ecma|java)script:!sim', $chunk ) ) {
|
||||
wfDebug( __METHOD__ . ": found css-style script urls\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
wfDebug( __METHOD__ . ": no scripts found\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1131,16 +1183,19 @@ abstract class UploadBase {
|
|||
&& !in_array( strtoupper( $encMatch[1] ), self::$safeXmlEncodings )
|
||||
) {
|
||||
wfDebug( __METHOD__ . ": Found unsafe XML encoding '{$encMatch[1]}'\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
} elseif ( preg_match( "!<\?xml\b!si", $contents ) ) {
|
||||
// Start of XML declaration without an end in the first $wgSVGMetadataCutoff
|
||||
// bytes. There shouldn't be a legitimate reason for this to happen.
|
||||
wfDebug( __METHOD__ . ": Unmatched XML declaration start\n" );
|
||||
|
||||
return true;
|
||||
} elseif ( substr( $contents, 0, 4 ) == "\x4C\x6F\xA7\x94" ) {
|
||||
// EBCDIC encoded XML
|
||||
wfDebug( __METHOD__ . ": EBCDIC Encoded XML\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1151,17 +1206,19 @@ abstract class UploadBase {
|
|||
wfSuppressWarnings();
|
||||
$str = iconv( $encoding, 'UTF-8', $contents );
|
||||
wfRestoreWarnings();
|
||||
if ( $str != '' && preg_match( "!<\?xml\b(.*?)\?>!si", $str, $matches ) ) {
|
||||
if ( $str != '' && preg_match( "!<\?xml\b(.*?)\?>!si", $str, $matches ) ) {
|
||||
if ( preg_match( $encodingRegex, $matches[1], $encMatch )
|
||||
&& !in_array( strtoupper( $encMatch[1] ), self::$safeXmlEncodings )
|
||||
) {
|
||||
wfDebug( __METHOD__ . ": Found unsafe XML encoding '{$encMatch[1]}'\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
} elseif ( $str != '' && preg_match( "!<\?xml\b!si", $str ) ) {
|
||||
// Start of XML declaration without an end in the first $wgSVGMetadataCutoff
|
||||
// bytes. There shouldn't be a legitimate reason for this to happen.
|
||||
wfDebug( __METHOD__ . ": Unmatched XML declaration start\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1188,8 +1245,10 @@ abstract class UploadBase {
|
|||
if ( $this->mSVGNSError ) {
|
||||
return array( 'uploadscriptednamespace', $this->mSVGNSError );
|
||||
}
|
||||
|
||||
return array( 'uploadscripted' );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1204,6 +1263,7 @@ abstract class UploadBase {
|
|||
if ( preg_match( '/xml-stylesheet/i', $target ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -1257,6 +1317,7 @@ abstract class UploadBase {
|
|||
wfDebug( __METHOD__ . ": Non-svg namespace '$namespace' in uploaded file.\n" );
|
||||
// @TODO return a status object to a closure in XmlTypeCheck, for MW1.21+
|
||||
$this->mSVGNSError = $namespace;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1265,24 +1326,28 @@ abstract class UploadBase {
|
|||
*/
|
||||
if ( $strippedElement == 'script' ) {
|
||||
wfDebug( __METHOD__ . ": Found script element '$element' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# e.g., <svg xmlns="http://www.w3.org/2000/svg"> <handler xmlns:ev="http://www.w3.org/2001/xml-events" ev:event="load">alert(1)</handler> </svg>
|
||||
if ( $strippedElement == 'handler' ) {
|
||||
wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# SVG reported in Feb '12 that used xml:stylesheet to generate javascript block
|
||||
if ( $strippedElement == 'stylesheet' ) {
|
||||
wfDebug( __METHOD__ . ": Found scriptable element '$element' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# Block iframes, in case they pass the namespace check
|
||||
if ( $strippedElement == 'iframe' ) {
|
||||
wfDebug( __METHOD__ . ": iframe in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1292,48 +1357,56 @@ abstract class UploadBase {
|
|||
|
||||
if ( substr( $stripped, 0, 2 ) == 'on' ) {
|
||||
wfDebug( __METHOD__ . ": Found event-handler attribute '$attrib'='$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# href with javascript target
|
||||
if ( $stripped == 'href' && strpos( strtolower( $value ), 'javascript:' ) !== false ) {
|
||||
wfDebug( __METHOD__ . ": Found script in href attribute '$attrib'='$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# href with embedded svg as target
|
||||
if ( $stripped == 'href' && preg_match( '!data:[^,]*image/svg[^,]*,!sim', $value ) ) {
|
||||
wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# href with embedded (text/xml) svg as target
|
||||
if ( $stripped == 'href' && preg_match( '!data:[^,]*text/xml[^,]*,!sim', $value ) ) {
|
||||
wfDebug( __METHOD__ . ": Found href to embedded svg \"<$strippedElement '$attrib'='$value'...\" in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# use set/animate to add event-handler attribute to parent
|
||||
if ( ( $strippedElement == 'set' || $strippedElement == 'animate' ) && $stripped == 'attributename' && substr( $value, 0, 2 ) == 'on' ) {
|
||||
wfDebug( __METHOD__ . ": Found svg setting event-handler attribute with \"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# use set to add href attribute to parent element
|
||||
if ( $strippedElement == 'set' && $stripped == 'attributename' && strpos( $value, 'href' ) !== false ) {
|
||||
wfDebug( __METHOD__ . ": Found svg setting href attribute '$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# use set to add a remote / data / script target to an element
|
||||
if ( $strippedElement == 'set' && $stripped == 'to' && preg_match( '!(http|https|data|script):!sim', $value ) ) {
|
||||
wfDebug( __METHOD__ . ": Found svg setting attribute to '$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
# use handler attribute with remote / data / script
|
||||
if ( $stripped == 'handler' && preg_match( '!(http|https|data|script):!sim', $value ) ) {
|
||||
wfDebug( __METHOD__ . ": Found svg setting handler with remote/data/script '$attrib'='$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -1343,6 +1416,7 @@ abstract class UploadBase {
|
|||
foreach ( $matches[1] as $match ) {
|
||||
if ( !preg_match( '!(?:font|clip-path|fill|filter|marker|marker-end|marker-mid|marker-start|mask|stroke)\s*:\s*url\s*\(\s*(#|\'#|"#)!sim', $match ) ) {
|
||||
wfDebug( __METHOD__ . ": Found svg setting a style with remote url '$attrib'='$value' in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1351,9 +1425,9 @@ abstract class UploadBase {
|
|||
# image filters can pull in url, which could be svg that executes scripts
|
||||
if ( $strippedElement == 'image' && $stripped == 'filter' && preg_match( '!url\s*\(!sim', $value ) ) {
|
||||
wfDebug( __METHOD__ . ": Found image filter with url: \"<$strippedElement $stripped='$value'...\" in uploaded file.\n" );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false; //No scripts detected
|
||||
|
|
@ -1369,6 +1443,7 @@ abstract class UploadBase {
|
|||
$parts = explode( ':', strtolower( $element ) );
|
||||
$name = array_pop( $parts );
|
||||
$ns = implode( ':', $parts );
|
||||
|
||||
return array( $ns, $name );
|
||||
}
|
||||
|
||||
|
|
@ -1379,6 +1454,7 @@ abstract class UploadBase {
|
|||
private function stripXmlNamespace( $name ) {
|
||||
// 'http://www.w3.org/2000/svg:script' -> 'script'
|
||||
$parts = explode( ':', strtolower( $name ) );
|
||||
|
||||
return array_pop( $parts );
|
||||
}
|
||||
|
||||
|
|
@ -1399,6 +1475,7 @@ abstract class UploadBase {
|
|||
if ( !$wgAntivirus ) {
|
||||
wfDebug( __METHOD__ . ": virus scanner disabled\n" );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -1407,6 +1484,7 @@ abstract class UploadBase {
|
|||
$wgOut->wrapWikiMsg( "<div class=\"error\">\n$1\n</div>",
|
||||
array( 'virus-badscanner', $wgAntivirus ) );
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return wfMessage( 'virus-unknownscanner' )->text() . " $wgAntivirus";
|
||||
}
|
||||
|
||||
|
|
@ -1478,6 +1556,7 @@ abstract class UploadBase {
|
|||
}
|
||||
|
||||
wfProfileOut( __METHOD__ );
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
|
@ -1589,7 +1668,7 @@ abstract class UploadBase {
|
|||
|
||||
// Check for files with the same name but a different extension
|
||||
$similarFiles = RepoGroup::singleton()->getLocalRepo()->findFilesByPrefix(
|
||||
"{$partname}.", 1 );
|
||||
"{$partname}.", 1 );
|
||||
if ( count( $similarFiles ) ) {
|
||||
return array(
|
||||
'warning' => 'exists-normalized',
|
||||
|
|
@ -1639,11 +1718,12 @@ abstract class UploadBase {
|
|||
public static function isThumbName( $filename ) {
|
||||
$n = strrpos( $filename, '.' );
|
||||
$partname = $n ? substr( $filename, 0, $n ) : $filename;
|
||||
|
||||
return (
|
||||
substr( $partname, 3, 3 ) == 'px-' ||
|
||||
substr( $partname, 2, 3 ) == 'px-'
|
||||
) &&
|
||||
preg_match( "/[0-9]{2}/", substr( $partname, 0, 2 ) );
|
||||
substr( $partname, 3, 3 ) == 'px-' ||
|
||||
substr( $partname, 2, 3 ) == 'px-'
|
||||
) &&
|
||||
preg_match( "/[0-9]{2}/", substr( $partname, 0, 2 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1670,6 +1750,7 @@ abstract class UploadBase {
|
|||
$blacklist[] = trim( $line );
|
||||
}
|
||||
}
|
||||
|
||||
return $blacklist;
|
||||
}
|
||||
|
||||
|
|
@ -1694,6 +1775,7 @@ abstract class UploadBase {
|
|||
$imParam = ApiQueryImageInfo::getPropertyNames();
|
||||
$info = ApiQueryImageInfo::getInfo( $file, array_flip( $imParam ), $result );
|
||||
}
|
||||
|
||||
return $info;
|
||||
}
|
||||
|
||||
|
|
@ -1704,6 +1786,7 @@ abstract class UploadBase {
|
|||
public function convertVerifyErrorToStatus( $error ) {
|
||||
$code = $error['status'];
|
||||
unset( $code['status'] );
|
||||
|
||||
return Status::newFatal( $this->getVerificationErrorCode( $code ), $error );
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
|
||||
// Update db table to reflect initial "chunk" state
|
||||
$this->updateChunkStatus();
|
||||
|
||||
return $this->mLocalFile;
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +155,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
if ( $ret['status'] !== UploadBase::OK ) {
|
||||
wfDebugLog( 'fileconcatenate', "Verification failed for chunked upload" );
|
||||
$status->fatal( $this->getVerificationErrorCode( $ret['status'] ) );
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
|
@ -178,6 +180,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
*/
|
||||
public function performUpload( $comment, $pageText, $watch, $user ) {
|
||||
$rv = parent::performUpload( $comment, $pageText, $watch, $user );
|
||||
|
||||
return $rv;
|
||||
}
|
||||
|
||||
|
|
@ -188,11 +191,11 @@ class UploadFromChunks extends UploadFromFile {
|
|||
*/
|
||||
function getVirtualChunkLocation( $index ) {
|
||||
return $this->repo->getVirtualUrl( 'temp' ) .
|
||||
'/' .
|
||||
$this->repo->getHashPath(
|
||||
$this->getChunkFileKey( $index )
|
||||
) .
|
||||
$this->getChunkFileKey( $index );
|
||||
'/' .
|
||||
$this->repo->getHashPath(
|
||||
$this->getChunkFileKey( $index )
|
||||
) .
|
||||
$this->getChunkFileKey( $index );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -234,6 +237,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
$status = Status::newFatal( 'invalid-chunk-offset' );
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +246,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
*/
|
||||
private function updateChunkStatus() {
|
||||
wfDebug( __METHOD__ . " update chunk status for {$this->mFileKey} offset:" .
|
||||
$this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n" );
|
||||
$this->getOffset() . ' inx:' . $this->getChunkIndex() . "\n" );
|
||||
|
||||
$dbw = $this->repo->getMasterDb();
|
||||
// Use a quick transaction since we will upload the full temp file into shared
|
||||
|
|
@ -294,6 +298,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
if ( $this->mChunkIndex !== null ) {
|
||||
return $this->mChunkIndex;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -305,6 +310,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
if ( $this->mOffset !== null ) {
|
||||
return $this->mOffset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -325,19 +331,20 @@ class UploadFromChunks extends UploadFromFile {
|
|||
$this->repo->getZonePath( 'temp' ) . "/{$hashPath}{$fileKey}" );
|
||||
|
||||
// Check for error in stashing the chunk:
|
||||
if ( ! $storeStatus->isOK() ) {
|
||||
if ( !$storeStatus->isOK() ) {
|
||||
$error = $storeStatus->getErrorsArray();
|
||||
$error = reset( $error );
|
||||
if ( ! count( $error ) ) {
|
||||
if ( !count( $error ) ) {
|
||||
$error = $storeStatus->getWarningsArray();
|
||||
$error = reset( $error );
|
||||
if ( ! count( $error ) ) {
|
||||
if ( !count( $error ) ) {
|
||||
$error = array( 'unknown', 'no error recorded' );
|
||||
}
|
||||
}
|
||||
throw new UploadChunkFileException( "Error storing file in '$chunkPath': " .
|
||||
implode( '; ', $error ) );
|
||||
}
|
||||
|
||||
return $storeStatus;
|
||||
}
|
||||
|
||||
|
|
@ -345,6 +352,7 @@ class UploadFromChunks extends UploadFromFile {
|
|||
if ( $index === null ) {
|
||||
$index = $this->getChunkIndex();
|
||||
}
|
||||
|
||||
return $this->mFileKey . '.' . $index;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@
|
|||
* @author Bryan Tong Minh
|
||||
*/
|
||||
class UploadFromFile extends UploadBase {
|
||||
|
||||
/**
|
||||
* @var WebRequestUpload
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -157,6 +157,7 @@ class UploadFromStash extends UploadBase {
|
|||
// replace mLocalFile with an instance of UploadStashFile, which adds some methods
|
||||
// that are useful for stashed files.
|
||||
$this->mLocalFile = parent::stashFile( $user );
|
||||
|
||||
return $this->mLocalFile;
|
||||
}
|
||||
|
||||
|
|
@ -187,6 +188,7 @@ class UploadFromStash extends UploadBase {
|
|||
public function performUpload( $comment, $pageText, $watch, $user ) {
|
||||
$rv = parent::performUpload( $comment, $pageText, $watch, $user );
|
||||
$this->unsaveUploadedFile();
|
||||
|
||||
return $rv;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ class UploadFromUrl extends UploadBase {
|
|||
if ( !$user->isAllowed( 'upload_by_url' ) ) {
|
||||
return 'upload_by_url';
|
||||
}
|
||||
|
||||
return parent::isAllowed( $user );
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +59,7 @@ class UploadFromUrl extends UploadBase {
|
|||
*/
|
||||
public static function isEnabled() {
|
||||
global $wgAllowCopyUploads;
|
||||
|
||||
return $wgAllowCopyUploads && parent::isEnabled();
|
||||
}
|
||||
|
||||
|
|
@ -103,6 +105,7 @@ class UploadFromUrl extends UploadBase {
|
|||
}
|
||||
*/
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
|
@ -118,6 +121,7 @@ class UploadFromUrl extends UploadBase {
|
|||
wfRunHooks( 'IsUploadAllowedFromUrl', array( $url, &$allowed ) );
|
||||
self::$allowedUrls[$url] = $allowed;
|
||||
}
|
||||
|
||||
return self::$allowedUrls[$url];
|
||||
}
|
||||
|
||||
|
|
@ -169,6 +173,7 @@ class UploadFromUrl extends UploadBase {
|
|||
global $wgUser;
|
||||
|
||||
$url = $request->getVal( 'wpUploadFileURL' );
|
||||
|
||||
return !empty( $url )
|
||||
&& Http::isValidURI( $url )
|
||||
&& $wgUser->isAllowed( 'upload_by_url' );
|
||||
|
|
@ -202,6 +207,7 @@ class UploadFromUrl extends UploadBase {
|
|||
if ( !$this->mAsync ) {
|
||||
return $this->reallyFetchFile( $httpOptions );
|
||||
}
|
||||
|
||||
return Status::newGood();
|
||||
}
|
||||
|
||||
|
|
@ -213,6 +219,7 @@ class UploadFromUrl extends UploadBase {
|
|||
protected function makeTemporaryFile() {
|
||||
$tmpFile = TempFSFile::factory( 'URL' );
|
||||
$tmpFile->bind( $this );
|
||||
|
||||
return $tmpFile->getPath();
|
||||
}
|
||||
|
||||
|
|
@ -259,12 +266,12 @@ class UploadFromUrl extends UploadBase {
|
|||
$this->mRemoveTempFile = true;
|
||||
$this->mFileSize = 0;
|
||||
|
||||
$options = $httpOptions + array(
|
||||
'followRedirects' => true,
|
||||
);
|
||||
$options = $httpOptions + array( 'followRedirects' => true );
|
||||
|
||||
if ( $wgCopyUploadProxy !== false ) {
|
||||
$options['proxy'] = $wgCopyUploadProxy;
|
||||
}
|
||||
|
||||
if ( $wgCopyUploadTimeout && !isset( $options['timeout'] ) ) {
|
||||
$options['timeout'] = $wgCopyUploadTimeout;
|
||||
}
|
||||
|
|
@ -297,6 +304,7 @@ class UploadFromUrl extends UploadBase {
|
|||
if ( $this->mAsync ) {
|
||||
return array( 'status' => UploadBase::OK );
|
||||
}
|
||||
|
||||
return parent::verifyUpload();
|
||||
}
|
||||
|
||||
|
|
@ -308,8 +316,10 @@ class UploadFromUrl extends UploadBase {
|
|||
public function checkWarnings() {
|
||||
if ( $this->mAsync ) {
|
||||
$this->mIgnoreWarnings = false;
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
return parent::checkWarnings();
|
||||
}
|
||||
|
||||
|
|
@ -323,6 +333,7 @@ class UploadFromUrl extends UploadBase {
|
|||
if ( $this->mAsync ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return parent::verifyTitlePermissions( $user );
|
||||
}
|
||||
|
||||
|
|
@ -367,7 +378,7 @@ class UploadFromUrl extends UploadBase {
|
|||
) );
|
||||
$job->initializeSessionData();
|
||||
JobQueueGroup::singleton()->push( $job );
|
||||
|
||||
return $sessionKey;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
* - enable applications to temporarily stash files without publishing them to the wiki.
|
||||
* - Several parts of MediaWiki do this in similar ways: UploadBase, UploadWizard, and FirefoggChunkedExtension
|
||||
* And there are several that reimplement stashing from scratch, in idiosyncratic ways. The idea is to unify them all here.
|
||||
* Mostly all of them are the same except for storing some custom fields, which we subsume into the data array.
|
||||
* Mostly all of them are the same except for storing some custom fields, which we subsume into the data array.
|
||||
* - enable applications to find said files later, as long as the db table or temp files haven't been purged.
|
||||
* - enable the uploading user (and *ONLY* the uploading user) to access said files, and thumbnails of said files, via a URL.
|
||||
* We accomplish this using a database table, with ownership checking as you might expect. See SpecialUploadStash, which
|
||||
|
|
@ -42,7 +42,6 @@
|
|||
* @ingroup Upload
|
||||
*/
|
||||
class UploadStash {
|
||||
|
||||
// Format of the key for files -- has to be suitable as a filename itself (e.g. ab12cd34ef.jpg)
|
||||
const KEY_FORMAT_REGEX = '/^[\w-\.]+\.\w*$/';
|
||||
|
||||
|
|
@ -106,7 +105,7 @@ class UploadStash {
|
|||
* @return UploadStashFile
|
||||
*/
|
||||
public function getFile( $key, $noAuth = false ) {
|
||||
if ( ! preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
|
||||
if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
|
||||
throw new UploadStashBadPathException( "key '$key' is not in a proper format" );
|
||||
}
|
||||
|
||||
|
|
@ -138,7 +137,7 @@ class UploadStash {
|
|||
}
|
||||
}
|
||||
|
||||
if ( ! $this->files[$key]->exists() ) {
|
||||
if ( !$this->files[$key]->exists() ) {
|
||||
wfDebug( __METHOD__ . " tried to get file at $key, but it doesn't exist\n" );
|
||||
throw new UploadStashBadPathException( "path doesn't exist" );
|
||||
}
|
||||
|
|
@ -160,6 +159,7 @@ class UploadStash {
|
|||
*/
|
||||
public function getMetadata( $key ) {
|
||||
$this->getFile( $key );
|
||||
|
||||
return $this->fileMetadata[$key];
|
||||
}
|
||||
|
||||
|
|
@ -171,6 +171,7 @@ class UploadStash {
|
|||
*/
|
||||
public function getFileProps( $key ) {
|
||||
$this->getFile( $key );
|
||||
|
||||
return $this->fileProps[$key];
|
||||
}
|
||||
|
||||
|
|
@ -215,7 +216,7 @@ class UploadStash {
|
|||
|
||||
$this->fileProps[$key] = $fileProps;
|
||||
|
||||
if ( ! preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
|
||||
if ( !preg_match( self::KEY_FORMAT_REGEX, $key ) ) {
|
||||
throw new UploadStashBadPathException( "key '$key' is not in a proper format" );
|
||||
}
|
||||
|
||||
|
|
@ -224,7 +225,7 @@ class UploadStash {
|
|||
// if not already in a temporary area, put it there
|
||||
$storeStatus = $this->repo->storeTemp( basename( $pathWithGoodExtension ), $path );
|
||||
|
||||
if ( ! $storeStatus->isOK() ) {
|
||||
if ( !$storeStatus->isOK() ) {
|
||||
// It is a convention in MediaWiki to only return one error per API exception, even if multiple errors
|
||||
// are available. We use reset() to pick the "first" thing that was wrong, preferring errors to warnings.
|
||||
// This is a bit lame, as we may have more info in the $storeStatus and we're throwing it away, but to fix it means
|
||||
|
|
@ -232,10 +233,10 @@ class UploadStash {
|
|||
// $storeStatus->value just contains the virtual URL (if anything) which is probably useless to the caller
|
||||
$error = $storeStatus->getErrorsArray();
|
||||
$error = reset( $error );
|
||||
if ( ! count( $error ) ) {
|
||||
if ( !count( $error ) ) {
|
||||
$error = $storeStatus->getWarningsArray();
|
||||
$error = reset( $error );
|
||||
if ( ! count( $error ) ) {
|
||||
if ( !count( $error ) ) {
|
||||
$error = array( 'unknown', 'no error recorded' );
|
||||
}
|
||||
}
|
||||
|
|
@ -451,6 +452,7 @@ class UploadStash {
|
|||
// put it in a web accesible directory.
|
||||
return '';
|
||||
}
|
||||
|
||||
return $extension;
|
||||
}
|
||||
|
||||
|
|
@ -502,6 +504,7 @@ class UploadStash {
|
|||
throw new UploadStashZeroLengthFileException( "File is zero length" );
|
||||
}
|
||||
$this->files[$key] = $file;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -528,17 +531,17 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
if ( $repo->isVirtualUrl( $path ) ) {
|
||||
$path = $repo->resolveVirtualUrl( $path );
|
||||
} else {
|
||||
|
||||
// check if path appears to be sane, no parent traversals, and is in this repo's temp zone.
|
||||
$repoTempPath = $repo->getZonePath( 'temp' );
|
||||
if ( ( ! $repo->validateFilename( $path ) ) ||
|
||||
( strpos( $path, $repoTempPath ) !== 0 ) ) {
|
||||
if ( ( !$repo->validateFilename( $path ) ) ||
|
||||
( strpos( $path, $repoTempPath ) !== 0 )
|
||||
) {
|
||||
wfDebug( "UploadStash: tried to construct an UploadStashFile from a file that should already exist at '$path', but path is not valid\n" );
|
||||
throw new UploadStashBadPathException( 'path is not valid' );
|
||||
}
|
||||
|
||||
// check if path exists! and is a plain file.
|
||||
if ( ! $repo->fileExists( $path ) ) {
|
||||
if ( !$repo->fileExists( $path ) ) {
|
||||
wfDebug( "UploadStash: tried to construct an UploadStashFile from a file that should already exist at '$path', but path is not found\n" );
|
||||
throw new UploadStashFileNotFoundException( 'cannot find path, or not a plain file' );
|
||||
}
|
||||
|
|
@ -574,6 +577,7 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
if ( $thumbName !== false ) {
|
||||
$path .= "/$thumbName";
|
||||
}
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
|
@ -610,6 +614,7 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
*/
|
||||
public function getThumbUrl( $thumbName = false ) {
|
||||
wfDebug( __METHOD__ . " getting for $thumbName \n" );
|
||||
|
||||
return $this->getSpecialUrl( 'thumb/' . $this->getUrlName() . '/' . $thumbName );
|
||||
}
|
||||
|
||||
|
|
@ -620,9 +625,10 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
* @return string Base url name, like '120px-123456.jpg'
|
||||
*/
|
||||
public function getUrlName() {
|
||||
if ( ! $this->urlName ) {
|
||||
if ( !$this->urlName ) {
|
||||
$this->urlName = $this->fileKey;
|
||||
}
|
||||
|
||||
return $this->urlName;
|
||||
}
|
||||
|
||||
|
|
@ -636,6 +642,7 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
if ( !isset( $this->url ) ) {
|
||||
$this->url = $this->getSpecialUrl( 'file/' . $this->getUrlName() );
|
||||
}
|
||||
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
|
|
@ -674,15 +681,32 @@ class UploadStashFile extends UnregisteredLocalFile {
|
|||
public function exists() {
|
||||
return $this->repo->fileExists( $this->path );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class UploadStashException extends MWException {};
|
||||
class UploadStashNotAvailableException extends UploadStashException {};
|
||||
class UploadStashFileNotFoundException extends UploadStashException {};
|
||||
class UploadStashBadPathException extends UploadStashException {};
|
||||
class UploadStashFileException extends UploadStashException {};
|
||||
class UploadStashZeroLengthFileException extends UploadStashException {};
|
||||
class UploadStashNotLoggedInException extends UploadStashException {};
|
||||
class UploadStashWrongOwnerException extends UploadStashException {};
|
||||
class UploadStashNoSuchKeyException extends UploadStashException {};
|
||||
class UploadStashException extends MWException {
|
||||
}
|
||||
|
||||
class UploadStashNotAvailableException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashFileNotFoundException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashBadPathException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashFileException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashZeroLengthFileException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashNotLoggedInException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashWrongOwnerException extends UploadStashException {
|
||||
}
|
||||
|
||||
class UploadStashNoSuchKeyException extends UploadStashException {
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue