Improve debugging and error handling for chunked file uploads

This commit is contained in:
Kijin Sung 2016-12-17 21:37:30 +09:00
parent 193fab949d
commit 13b14dc7f5
5 changed files with 103 additions and 22 deletions

View file

@ -63,20 +63,23 @@
var currentEnforce_ssl = window.enforce_ssl; var currentEnforce_ssl = window.enforce_ssl;
if(location.protocol == 'https:') { window.enforce_ssl = true; } if(location.protocol == 'https:') { window.enforce_ssl = true; }
var settings = { var chunkStatus = true;
url: request_uri, var defaultFormData = {
formData: {
"editor_sequence": data.editorSequence, "editor_sequence": data.editorSequence,
"upload_target_srl" : data.uploadTargetSrl, "upload_target_srl" : data.uploadTargetSrl,
"mid" : window.current_mid, "mid" : window.current_mid,
"act": 'procFileUpload' "act": 'procFileUpload'
}, };
var settings = {
url: request_uri,
formData: defaultFormData,
dropZone: $container, dropZone: $container,
add: function(e, d) { add: function(e, d) {
var dfd = jQuery.Deferred(); var dfd = jQuery.Deferred();
$.each(d.files, function(index, file) { $.each(d.files, function(index, file) {
if(data.settings.maxFileSize <= file.size) { if(data.settings.maxFileSize > 0 && data.settings.maxFileSize < file.size) {
dfd.reject(); dfd.reject();
alert(window.xe.msg_exceeds_limit_size); alert(window.xe.msg_exceeds_limit_size);
return false; return false;
@ -88,15 +91,51 @@
d.submit(); d.submit();
}); });
}, },
submit: function(e, data) {
data.formData = defaultFormData;
data.formData.nonce = "T" + new Date().getTime() + "." + Math.random();
chunkStatus = true;
},
chunksend: function(e, data) {
if (!chunkStatus) {
return false;
}
},
chunkdone: function(e, res) {
if (res.result) {
if (res.result.error != 0) {
if (res.result.message) {
alert(res.result.message);
} else {
alert(window.xe.msg_file_upload_error + " (Type 1)");
}
return chunkStatus = false;
}
} else {
alert(window.xe.msg_file_upload_error + " (Type 2)");
return chunkStatus = false;
}
},
chunkfail: function(e, data) {
if (chunkStatus) {
alert(window.xe.msg_file_upload_error + " (Type 3)" + "\n" + data.errorThrown + "\n" + data.textStatus);
return chunkStatus = false;
}
},
done: function(e, res) { done: function(e, res) {
var result = res.response().result; var result = res.response().result;
var temp_code = ''; var temp_code = '';
if (!result) {
if(!result) return; alert(window.xe.msg_file_upload_error + " (Type 4)");
return false;
if(!jQuery.isPlainObject(result)) result = jQuery.parseJSON(result); }
if (!jQuery.isPlainObject(result)) {
if(!result) return; result = jQuery.parseJSON(result);
}
if (!result) {
alert(window.xe.msg_file_upload_error + " (Type 5)");
return false;
}
if(result.error == 0) { if(result.error == 0) {
if(/\.(jpe?g|png|gif)$/i.test(result.source_filename)) { if(/\.(jpe?g|png|gif)$/i.test(result.source_filename)) {
@ -105,8 +144,18 @@
} }
_getCkeInstance(settings.formData.editor_sequence).insertHtml(temp_code, "unfiltered_html"); _getCkeInstance(settings.formData.editor_sequence).insertHtml(temp_code, "unfiltered_html");
} else { } else if (result.message) {
alert(result.message); alert(result.message);
return false;
} else {
alert(window.xe.msg_file_upload_error + " (Type 6)");
return false;
}
},
fail: function(e, data) {
if (chunkStatus) {
alert(window.xe.msg_file_upload_error + " (Type 7)" + "\n" + data.errorThrown + "\n" + data.textStatus);
return false;
} }
}, },
stop: function() { stop: function() {

View file

@ -305,8 +305,15 @@ class editorModel extends editor
$file_config = $oFileModel->getUploadConfig(); $file_config = $oFileModel->getUploadConfig();
$file_config->allowed_attach_size = $file_config->allowed_attach_size*1024*1024; $file_config->allowed_attach_size = $file_config->allowed_attach_size*1024*1024;
$file_config->allowed_filesize = $file_config->allowed_filesize*1024*1024; $file_config->allowed_filesize = $file_config->allowed_filesize*1024*1024;
$file_config->allowed_chunk_size = min(FileHandler::returnBytes(ini_get('upload_max_filesize')), FileHandler::returnBytes(ini_get('post_max_size')) * 0.95, 100 * 1024 * 1024); $file_config->allowed_chunk_size = min(FileHandler::returnBytes(ini_get('upload_max_filesize')), FileHandler::returnBytes(ini_get('post_max_size')) * 0.95, 64 * 1024 * 1024);
$file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 131072) * 131072; if ($file_config->allowed_chunk_size > 4 * 1048576)
{
$file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 1048576) * 1048576;
}
else
{
$file_config->allowed_chunk_size = floor($file_config->allowed_chunk_size / 65536) * 65536;
}
Context::set('file_config',$file_config); Context::set('file_config',$file_config);
// Configure upload status such as file size // Configure upload status such as file size

View file

@ -67,7 +67,8 @@ class fileController extends file
} }
// Check existing chunks // Check existing chunks
$temp_key = hash_hmac('sha1', sprintf('%d:%d:%d:%s', $editor_sequence, $upload_target_srl, $module_srl, $file_info['name']), config('crypto.authentication_key')); $nonce = Context::get('nonce');
$temp_key = hash_hmac('sha1', sprintf('%d:%d:%d:%s:%s', $editor_sequence, $upload_target_srl, $module_srl, $file_info['name'], $nonce), config('crypto.authentication_key'));
$temp_filename = RX_BASEDIR . 'files/attach/chunks/' . $temp_key; $temp_filename = RX_BASEDIR . 'files/attach/chunks/' . $temp_key;
if ($chunk_start == 0 && Rhymix\Framework\Storage::isFile($temp_filename)) if ($chunk_start == 0 && Rhymix\Framework\Storage::isFile($temp_filename))
{ {
@ -79,6 +80,11 @@ class fileController extends file
Rhymix\Framework\Storage::delete($temp_filename); Rhymix\Framework\Storage::delete($temp_filename);
return new Object(-1, 'msg_upload_invalid_chunk'); return new Object(-1, 'msg_upload_invalid_chunk');
} }
if ($chunk_start >= 2 * 1024 * 1024)
{
Rhymix\Framework\Storage::delete($temp_filename);
return new Object(-1, 'msg_upload_invalid_chunk');
}
// Check size limit // Check size limit
$is_admin = (Context::get('logged_info')->is_admin === 'Y'); $is_admin = (Context::get('logged_info')->is_admin === 'Y');
@ -116,7 +122,7 @@ class fileController extends file
else else
{ {
Rhymix\Framework\Storage::delete($temp_filename); Rhymix\Framework\Storage::delete($temp_filename);
return new Object(-1, 'msg_upload_chunk_append_failed'); return new Object(-1, 'msg_upload_invalid_chunk');
} }
} }
@ -829,23 +835,40 @@ class fileController extends file
} }
// Move the file // Move the file
if($manual_insert || starts_with(RX_BASEDIR . 'files/attach/chunks/', $file_info['tmp_name'])) $filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext;
if($manual_insert)
{ {
@copy($file_info['tmp_name'], $filename); @copy($file_info['tmp_name'], $filename);
if(!file_exists($filename)) if(!file_exists($filename))
{ {
$filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext;
@copy($file_info['tmp_name'], $filename); @copy($file_info['tmp_name'], $filename);
if(!file_exists($filename))
{
return new Object(-1,'msg_file_upload_error');
}
}
}
elseif(starts_with(RX_BASEDIR . 'files/attach/chunks/', $file_info['tmp_name']))
{
if (!Rhymix\Framework\Storage::move($file_info['tmp_name'], $filename))
{
if (!Rhymix\Framework\Storage::move($file_info['tmp_name'], $filename))
{
return new Object(-1,'msg_file_upload_error');
}
} }
} }
else else
{ {
if(!@move_uploaded_file($file_info['tmp_name'], $filename)) if(!@move_uploaded_file($file_info['tmp_name'], $filename))
{ {
$filename = $path . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $ext; if(!@move_uploaded_file($file_info['tmp_name'], $filename))
if(!@move_uploaded_file($file_info['tmp_name'], $filename)) return new Object(-1,'msg_file_upload_error'); {
return new Object(-1,'msg_file_upload_error');
} }
} }
}
// Get member information // Get member information
$oMemberModel = getModel('member'); $oMemberModel = getModel('member');
$member_srl = $oMemberModel->getLoggedMemberSrl(); $member_srl = $oMemberModel->getLoggedMemberSrl();

View file

@ -44,6 +44,7 @@ $lang->file_search_target_list['isvalid'] = 'Status';
$lang->msg_not_allowed_outlink = 'It is not allowed to download files from sites other than this.'; $lang->msg_not_allowed_outlink = 'It is not allowed to download files from sites other than this.';
$lang->msg_not_permitted_create = 'Failed to create a file or directory.'; $lang->msg_not_permitted_create = 'Failed to create a file or directory.';
$lang->msg_file_upload_error = 'An error has occurred during uploading.'; $lang->msg_file_upload_error = 'An error has occurred during uploading.';
$lang->msg_upload_invalid_chunk = 'An error has occurred during chunked uploading.';
$lang->no_files = 'No Files'; $lang->no_files = 'No Files';
$lang->file_manager = 'Manage selected files'; $lang->file_manager = 'Manage selected files';
$lang->selected_file = 'Selected files'; $lang->selected_file = 'Selected files';

View file

@ -45,6 +45,7 @@ $lang->file_search_target_list['isvalid'] = '상태';
$lang->msg_not_allowed_outlink = '외부링크에서 다운로드할 수 없습니다.'; $lang->msg_not_allowed_outlink = '외부링크에서 다운로드할 수 없습니다.';
$lang->msg_not_permitted_create = '파일 또는 디렉터리를 생성할 수 없습니다.'; $lang->msg_not_permitted_create = '파일 또는 디렉터리를 생성할 수 없습니다.';
$lang->msg_file_upload_error = '파일 업로드 중 에러가 발생하였습니다.'; $lang->msg_file_upload_error = '파일 업로드 중 에러가 발생하였습니다.';
$lang->msg_upload_invalid_chunk = '분할 업로드 처리 중 오류가 발생하였습니다.';
$lang->no_files = '파일이 없습니다.'; $lang->no_files = '파일이 없습니다.';
$lang->file_manager = '선택한 파일 관리'; $lang->file_manager = '선택한 파일 관리';
$lang->selected_file = '선택한 파일'; $lang->selected_file = '선택한 파일';