r50147 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r50146‎ | r50147 | r50148 >
Date:00:55, 3 May 2009
Author:dale
Status:deferred
Tags:
Comment:
session upload code fixes
Modified paths:
  • /branches/new-upload/phase3/api.php (modified) (history)
  • /branches/new-upload/phase3/includes/GlobalFunctions.php (modified) (history)
  • /branches/new-upload/phase3/includes/HttpFunctions.php (modified) (history)
  • /branches/new-upload/phase3/includes/UploadFromUrl.php (modified) (history)
  • /branches/new-upload/phase3/includes/api/ApiMain.php (modified) (history)
  • /branches/new-upload/phase3/includes/api/ApiUpload.php (modified) (history)

Diff [purge]

Index: branches/new-upload/phase3/includes/GlobalFunctions.php
@@ -2189,7 +2189,13 @@
21902190 *
21912191 * @param string $cmd
21922192 */
2193 -function wfShellBackgroundExec(&$cmd){
 2193+function wfShellBackgroundExec( $cmd ){
 2194+ wfDebug( "wfShellBackgroundExec: $cmd\n" );
 2195+
 2196+ if ( ! wfShellExecEnabled() ) {
 2197+ return "Unable to run external programs";
 2198+ }
 2199+
21942200 $pid = shell_exec( "nohup $cmd > /dev/null & echo $!" );
21952201 return $pid;
21962202 }
Index: branches/new-upload/phase3/includes/api/ApiMain.php
@@ -375,7 +375,7 @@
376376 /**
377377 * Execute the actual module, without any error handling
378378 */
379 - protected function executeAction() {
 379+ protected function executeAction() {
380380 // First add the id to the top element
381381 $requestid = $this->getParameter('requestid');
382382 if(!is_null($requestid))
@@ -425,10 +425,10 @@
426426
427427 if ($this->mPrinter->getNeedsRawData())
428428 $this->getResult()->setRawMode();
429 - }
430 -
 429+ }
431430 // Execute
432431 $module->profileIn();
 432+
433433 $module->execute();
434434 wfRunHooks('APIAfterExecute', array(&$module));
435435 $module->profileOut();
Index: branches/new-upload/phase3/includes/api/ApiUpload.php
@@ -63,7 +63,39 @@
6464 //if getAPIresult did not exit report the status error:
6565 if( isset( $this->mUpload->status[ 'error' ] ) )
6666 $this->dieUsageMsg( $this->mUpload->status[ 'error' ] );
67 -
 67+ }else if( $this->mParams['internalSession'] ){
 68+
 69+ wfDebug("execFromSession: $tempPath");
 70+ //get the params from the init session:
 71+
 72+ $fileSize = filesize($tempPath);
 73+
 74+ $this->mUpload = new UploadFromUpload();
 75+ $this->mUpload->initialize( $this->mParams['filename'], $tempPath, $fileSize);
 76+ if( !isset( $this->mUpload ) )
 77+ $this->dieUsage( 'No upload module set', 'nomodule' );
 78+
 79+ }else if( $this->mParams['httpstatus'] && $this->mParams['sessionkey']){
 80+ //return the status of the given upload session_key:
 81+ if(!isset($_SESSION['wsDownload'][ $this->mParams['sessionkey'] ])){
 82+ return $this->getResult()->addValue( null, $this->getModuleName(),
 83+ array( 'error' => 'invalid-session-key'
 84+ ));
 85+ }
 86+ $sd = & $_SESSION['wsDownload'][ $this->mParams['sessionkey'] ];
 87+ //keep passing down the upload sessionkey
 88+ $statusResult = array(
 89+ 'upload_session_key' => $this->mParams['sessionkey']
 90+ );
 91+
 92+ //put values into the final apiResult if available
 93+ if( isset($sd['apiUploadResult'])) $statusResult['apiUploadResult'] = $sd['apiUploadResult'];
 94+ if( isset($sd['loaded']) ) $statusResult['loaded'] = $sd['loaded'];
 95+ if( isset($sd['content_length']) ) $statusResult['content_length'] = $sd['content_length'];
 96+
 97+ return $this->getResult()->addValue( null, $this->getModuleName(),
 98+ $statusResult
 99+ );
68100 }else if( $this->mParams['sessionkey'] ) {
69101 // Stashed upload
70102 $this->mUpload = new UploadFromStash();
@@ -116,25 +148,7 @@
117149
118150 //finish up the exec command:
119151 $this->doExecUpload();
120 - }
121 - /**
122 - * alternate entry point
123 - */
124 - function execFromSession($tempPath){
125 - wfDebug("execFromSession: $tempPath");
126 - //get the params from the init session:
127 - $this->mParams = $this->extractRequestParams();
128 -
129 - $fileSize = filesize($tempPath);
130 -
131 - $this->mUpload = new UploadFromUpload();
132 - $this->mUpload->initialize( $this->mParams['filename'], $tempPath, $fileSize);
133 - if( !isset( $this->mUpload ) )
134 - $this->dieUsage( 'No upload module set', 'nomodule' );
135 -
136 - //finish up the exec command as a normal request:
137 - $this->doExecUpload();
138 - }
 152+ }
139153 function doExecUpload(){
140154 global $wgUser;
141155 //Check whether the user has the appropriate permissions to upload anyway
@@ -260,7 +274,7 @@
261275 'filename' => null,
262276 'file' => null,
263277 'chunk' => null,
264 - 'url' => null,
 278+ 'url' => null,
265279 'enablechunks' => null,
266280 'comment' => array(
267281 ApiBase :: PARAM_DFLT => ''
@@ -269,6 +283,7 @@
270284 'ignorewarnings' => false,
271285 'done' => false,
272286 'sessionkey' => null,
 287+ 'httpstatus' => null,
273288 'chunksessionkey'=> null
274289 );
275290 }
@@ -285,6 +300,7 @@
286301 'ignorewarnings' => 'Ignore any warnings',
287302 'done' => 'When used with "chunks", Is sent to notify the api The last chunk is being uploaded.',
288303 'sessionkey' => 'Session key in case there were any warnings.',
 304+ 'httpstatus' => 'When set to true, will return the status of a given sessionKey (used for progress meters)',
289305 'chunksessionkey'=> 'Used to sync uploading of chunks',
290306 );
291307 }
Index: branches/new-upload/phase3/includes/UploadFromUrl.php
@@ -26,8 +26,8 @@
2727
2828 $local_file = tempnam( $wgTmpDirectory, 'WEBUPLOAD' );
2929 parent::initialize( $name, $local_file, 0, true );
30 -
31 - $this->mUrl = trim( $url );
 30+
 31+ $this->mUrl = trim( $url );
3232 }
3333 public function isAsync(){
3434 return $this->dl_mode == Http::ASYNC_DOWNLOAD;
Index: branches/new-upload/phase3/includes/HttpFunctions.php
@@ -31,14 +31,15 @@
3232 global $wgPhpCliPath, $wgMaxUploadSize;
3333 //do a quick check to HEAD to insure the file size is not > $wgMaxUploadSize to large no need to download it
3434 $head = get_headers($url, 1);
35 - if(isset($head['Content-Length']) && $head['Content-Length'] > $wgMaxUploadSize){
 35+ if($head['Content-Length'] > $wgMaxUploadSize){
3636 return Status::newFatal('requested file length ' . $head['Content-Length'] . ' is greater than $wgMaxUploadSize: ' . $wgMaxUploadSize);
3737 }
 38+ $content_length = (isset($head['Content-Length']))?$head['Content-Length']:null;
3839 //check if we can find phpCliPath (for doing a background shell request to php to do the download:
3940 if( $wgPhpCliPath && wfShellExecEnabled() && $dl_mode == self::ASYNC_DOWNLOAD){
4041 wfDebug("\ASYNC_DOWNLOAD\n");
4142 //setup session and shell call:
42 - return self::initBackgroundDownload( $url, $target_file_path );
 43+ return self::initBackgroundDownload( $url, $target_file_path, $content_length );
4344 }else if( $dl_mode== self::SYNC_DOWNLOAD ){
4445 wfDebug("\nSYNC_DOWNLOAD\n");
4546 //SYNC_DOWNLOAD download as much as we can in the time we have to execute
@@ -53,7 +54,7 @@
5455 * should write to a file location and give updates
5556 *
5657 */
57 - private function initBackgroundDownload( $url, $target_file_path ){
 58+ private function initBackgroundDownload( $url, $target_file_path, $content_length = null ){
5859 global $wgMaxUploadSize, $IP, $wgPhpCliPath;
5960 $status = Status::newGood();
6061
@@ -63,8 +64,15 @@
6465
6566 //store the url and target path:
6667 $_SESSION[ 'wsDownload' ][$upload_session_key]['url'] = $url;
67 - $_SESSION[ 'wsDownload' ][$upload_session_key]['target_file_path'] = $target_file_path;
 68+ $_SESSION[ 'wsDownload' ][$upload_session_key]['target_file_path'] = $target_file_path;
6869
 70+ if($content_length)
 71+ $_SESSION[ 'wsDownload' ][$upload_session_key]['content_length'] = $content_length;
 72+
 73+ //set initial loaded bytes:
 74+ $_SESSION[ 'wsDownload' ][$upload_session_key]['loaded'] = 0;
 75+
 76+
6977 //run the background download request:
7078 $cmd = $wgPhpCliPath . ' ' . $IP . "/maintenance/http_session_download.php --sid {$session_id} --usk {$upload_session_key}";
7179 $pid = wfShellBackgroundExec($cmd , $retval);
@@ -76,7 +84,7 @@
7785 //update the status value with the $upload_session_key (for the user to check on the status of the upload)
7886 $status->value = $upload_session_key;
7987
80 - //return good status with
 88+ //return good status
8189 return $status;
8290 }
8391 function getUploadSessionKey(){
@@ -92,7 +100,7 @@
93101 * (a given client could have started a few http uploads at once)
94102 */
95103 public static function doSessionIdDownload( $session_id, $upload_session_key ){
96 - global $wgUser;
 104+ global $wgUser, $wgEnableWriteAPI;
97105 wfDebug("\n\ndoSessionIdDownload\n\n");
98106 //set session to the provided key:
99107 session_id($session_id);
@@ -109,45 +117,46 @@
110118 $wgUser = User::newFromSession();
111119
112120 //grab the session data to setup the request:
113 - $sessionData = $_SESSION[ 'wsDownload' ][$upload_session_key];
 121+ $sd =& $_SESSION[ 'wsDownload' ][$upload_session_key];
114122 //close down the session so we can other http queries can get session updates:
115123 session_write_close();
116124
117 - $req = new HttpRequest( $sessionData['url'], array(
118 - 'target_file_path' => $sessionData['target_file_path'],
 125+ $req = new HttpRequest( $sd['url'], array(
 126+ 'target_file_path' => $sd['target_file_path'],
119127 'upload_session_key' => $upload_session_key
120128 ) );
121129 //run the actual request .. (this can take some time)
122 - wfDebug("do Request: " . $sessionData['url'] . ' tf: ' .$sessionData['target_file_path'] );
 130+ wfDebug("do Request: " . $sd['url'] . ' tf: ' . $sd['target_file_path'] );
123131 $status = $req->doRequest();
124 -
 132+ wfDebug("done with req status is: ". $status->isOK(). ' '.$status->value. "\n");
125133 if( $status->isOK() ){
126134 //start up the session again:
127135 if( session_start() === false){
128136 wfDebug( __METHOD__ . ' ERROR:: Could not start session');
129 - }
 137+ }
130138 //re-grab the updated session data:
131 - $sessionData = $_SESSION[ 'wsDownload' ][$upload_session_key];
132 - $reqData = $sessionData['mParam'];
 139+ $sd =& $_SESSION[ 'wsDownload' ][$upload_session_key];
 140+
 141+ //setup the faxRequest
 142+ $fauxReqData = $sd['mParams'];
 143+ $fauxReqData['action'] = 'upload';
 144+ $fauxReqData['format'] = 'json';
 145+ $fauxReqData['internalSession'] = true;
 146+ $fauxReqData['sessionkey'] = $upload_session_key;
 147+ //evil but no other clean way about it:
133148
134 - $reqData['action'] = 'upload';
135149
136 - wfDebug('running FauxRequest: ' . print_r($reqData, true) );
137 -
138 - $faxReq = new FauxRequest($reqData, true);
 150+ $faxReq = new FauxRequest($fauxReqData, true);
139151 $processor = new ApiMain($faxReq, $wgEnableWriteAPI);
140 -
141 - //init the mUpload var for the $processor
142 - $processor->execFromSession($sessionData['target_file_path']);
143 -
 152+ //init the mUpload var for the $processor
144153 ob_start();
145 - $processor->doExecUpload();
 154+ $processor->execute();
146155 $apiUploadResult = ob_get_contents();
147156 ob_get_clean();
148157
149 -
 158+ wfDebug(":: $apiUploadResult \n" );
150159 //the status updates runner will grab the result form the session:
151 - $_SESSION[ 'wsDownload' ][$upload_session_key]['apiUploadResult'] = $apiUploadResult;
 160+ $sd['apiUploadResult'] = $apiUploadResult;
152161 session_write_close();
153162 }
154163 }
@@ -222,9 +231,7 @@
223232 private function doCurlReq(){
224233 global $wgHTTPFileTimeout, $wgHTTPProxy, $wgTitle;
225234
226 - $status = Status::newGood();
227 - wfDebug("\ncurReq: $this->url (sleep 1 sec)\n");
228 - sleep(1);
 235+ $status = Status::newGood();
229236 $c = curl_init( $this->url );
230237
231238 //proxy setup:
@@ -278,8 +285,7 @@
279286 }
280287 } catch (Exception $e) {
281288 //do something with curl exec error?
282 - }
283 - wfDebug("\nDONE WITH curl_exec \n");
 289+ }
284290 //if direct request output the results to the stats value:
285291 if( !$this->target_file_path && $status->isOK() ){
286292 $status->value = ob_get_contents();
@@ -344,8 +350,9 @@
345351 var $session_id = null;
346352 var $session_update_interval = 0; //how offten to update the session while downloading
347353
348 - function simpleFileWriter($target_file_path, $session_id=false){
 354+ function simpleFileWriter($target_file_path, $upload_session_key){
349355 $this->target_file_path = $target_file_path;
 356+ $this->upload_session_key = $upload_session_key;
350357 $this->status = Status::newGood();
351358 //open the file:
352359 $this->fp = fopen( $this->target_file_path, 'w');
@@ -356,8 +363,15 @@
357364 $this->prevTime = time();
358365 }
359366 public function callbackWriteBody($ch, $data_packet){
360 - global $wgMaxUploadSize;
361 - wfDebug("\ncallbackWriteBody::" . strlen($data_packet) . "\n");
 367+ global $wgMaxUploadSize;
 368+
 369+ //write out the content
 370+ if( fwrite($this->fp, $data_packet) === false){
 371+ wfDebug(__METHOD__ ." ::could-not-write-to-file\n");
 372+ $this->status = Status::newFatal('HTTP::could-not-write-to-file');
 373+ return 0;
 374+ }
 375+
362376 //check file size:
363377 clearstatcache();
364378 $this->current_fsize = filesize( $this->target_file_path);
@@ -367,19 +381,12 @@
368382 $this->status = Status::newFatal('HTTP::file-has-grown-beyond-upload-limit-killing: downloaded more than ' .
369383 Language::formatSize($wgMaxUploadSize) . ' ');
370384 return 0;
371 - }
372 - wfDebug("passed fsize check\n");
373 - //write out the content
374 - if( fwrite($this->fp, $data_packet) === false){
375 - wfDebug(__METHOD__ ." ::could-not-write-to-file\n");
376 - $this->status = Status::newFatal('HTTP::could-not-write-to-file');
377 - return 0;
378 - }
379 - wfDebug("did fwrite oky\n");
380 -
381 - wfDebug("\n" .'check if we should update: ' . time() . ' - ' .$this->prevTime . ' > '. $this->session_update_interval . "\n");
382 - //if more than 2 second have passed update_session_progress
383 - if($this->upload_session_key && (time() - $this->prevTime) > $this->session_update_interval ) {
 385+ }
 386+ //wfDebug('simulating slow download....'."\n");
 387+ sleep(1);
 388+
 389+ //if more than session_update_interval second have passed update_session_progress
 390+ if($this->upload_session_key && ( (time() - $this->prevTime) > $this->session_update_interval )) {
384391 $this->prevTime = time();
385392 $session_status = $this->update_session_progress();
386393 if( !$session_status->isOK() ){
@@ -387,8 +394,8 @@
388395 wfDebug( __METHOD__ . ' update session failed or was canceled');
389396 return 0;
390397 }
391 - }
392 - return strlen($data_packet);
 398+ }
 399+ return strlen( $data_packet );
393400 }
394401 public function update_session_progress(){
395402 $status = Status::newGood();
@@ -396,8 +403,8 @@
397404 if( session_start() === false){
398405 wfDebug( __METHOD__ . ' could not start session');
399406 exit(0);
400 - }
401 - $sd =& $_SESSION[ 'wsDownload' ][$this->upload_session_key];
 407+ }
 408+ $sd =& $_SESSION[ 'wsDownload' ][ $this->upload_session_key ];
402409 //check if the user canceled the request:
403410 if( $sd['user_cancel'] == true ){
404411 //kill the download
@@ -405,12 +412,15 @@
406413 }
407414 //update the progress bytes download so far:
408415 $sd['loaded'] = $this->current_fsize;
409 - wfDebug('set session loaded amount to: ' . $sd['loaded']);
 416+ wfDebug('set session loaded amount to: ' . $sd['loaded'] . "\n");
410417 //close down the session so we can other http queries can get session updates:
411418 session_write_close();
412419 return $status;
413420 }
414 - public function close(){
 421+ public function close(){
 422+ //do a final session update:
 423+ $this->update_session_progress();
 424+ //close up the file handle:
415425 if(false === fclose( $this->fp )){
416426 $this->status = Status::newFatal('HTTP::could-not-close-file');
417427 }
Index: branches/new-upload/phase3/api.php
@@ -72,7 +72,6 @@
7373 * but we don't care here, as that is handled by the ctor.
7474 */
7575 $processor = new ApiMain($wgRequest, $wgEnableWriteAPI);
76 -
7776 // Process data & print results
7877 $processor->execute();
7978

Status & tagging log