示例#1
0
        private void processMakeBlocks(Dictionary <long, byte[]> blockDataDict, string upToken,
                                       PutExtra putExtra, ResumeInfo resumeInfo, Dictionary <long, HttpResult> blockMakeResults,
                                       Dictionary <string, long> uploadedBytesDict, long fileSize)
        {
            int taskMax = blockDataDict.Count;

            ManualResetEvent[] doneEvents = new ManualResetEvent[taskMax];
            int    eventIndex             = 0;
            object progressLock           = new object();

            foreach (long blockIndex in blockDataDict.Keys)
            {
                //signal task
                ManualResetEvent doneEvent = new ManualResetEvent(false);
                doneEvents[eventIndex] = doneEvent;
                eventIndex            += 1;

                //queue task
                byte[]        blockData     = blockDataDict[blockIndex];
                ResumeBlocker resumeBlocker = new ResumeBlocker(doneEvent, blockData, blockIndex, upToken, putExtra,
                                                                resumeInfo, blockMakeResults, progressLock, uploadedBytesDict, fileSize);
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.MakeBlock), resumeBlocker);
            }

            try
            {
                WaitHandle.WaitAll(doneEvents);
            }
            catch (Exception ex)
            {
                Console.WriteLine("wait all exceptions:" + ex.StackTrace);
                //pass
            }
        }
示例#2
0
 /// <summary>
 /// 分片上传,支持断点续上传,带有自定义进度处理、高级控制功能
 /// </summary>
 /// <param name="localFile">本地待上传的文件名</param>
 /// <param name="key">要保存的文件名称</param>
 /// <param name="token">上传凭证</param>
 /// <param name="putExtra">上传可选配置</param>
 /// <returns>上传文件后的返回结果</returns>
 public HttpResult UploadFile(string localFile, string key, string token, PutExtra putExtra)
 {
     try
     {
         var stream = IOUtils.Api.OpenStreamForRead(localFile);
         return(this.UploadStream(stream, key, token, putExtra));
     }
     catch (Exception ex)
     {
         HttpResult ret = HttpResult.InvalidFile;
         ret.RefText = ex.Message;
         return(ret);
     }
 }
示例#3
0
 /// <summary>
 /// 上传文件 - 可附加自定义参数
 /// </summary>
 /// <param name="localFile">待上传的本地文件</param>
 /// <param name="key">要保存的目标文件名称</param>
 /// <param name="token">上传凭证</param>
 /// <param name="extra">上传可选设置</param>
 /// <returns>上传文件后的返回结果</returns>
 public HttpResult UploadFile(string localFile, string key, string token, PutExtra extra)
 {
     try
     {
         FileStream fs = new FileStream(localFile, FileMode.Open);
         return(this.UploadStream(fs, key, token, extra));
     }
     catch (Exception ex)
     {
         HttpResult ret = HttpResult.InvalidFile;
         ret.RefText = ex.Message;
         return(ret);
     }
 }
示例#4
0
 public ResumeBlocker(ManualResetEvent doneEvent, byte[] blockBuffer, long blockIndex, string uploadToken,
                      PutExtra putExtra, ResumeInfo resumeInfo, Dictionary <long, HttpResult> blockMakeResults,
                      object progressLock, Dictionary <string, long> uploadedBytesDict, long fileSize)
 {
     this.DoneEvent         = doneEvent;
     this.BlockBuffer       = blockBuffer;
     this.BlockIndex        = blockIndex;
     this.UploadToken       = uploadToken;
     this.PutExtra          = putExtra;
     this.ResumeInfo        = resumeInfo;
     this.BlockMakeResults  = blockMakeResults;
     this.ProgressLock      = progressLock;
     this.UploadedBytesDict = uploadedBytesDict;
     this.FileSize          = fileSize;
 }
示例#5
0
        /// <summary>
        /// 上传文件数据流,根据文件大小以及设置的阈值(用户初始化UploadManager时可指定该值)自动选择:
        /// 若文件大小超过设定阈值,使用ResumableUploader,否则使用FormUploader
        /// </summary>
        /// <param name="stream">待上传的数据流</param>
        /// <param name="key">要保存的文件名称</param>
        /// <param name="token">上传凭证</param>
        /// <param name="extra">上传可选设置</param>
        /// <returns>上传文件后的返回结果</returns>
        public HttpResult UploadStream(Stream stream, string key, string token, PutExtra extra)
        {
            HttpResult result = new HttpResult();

            if (stream.Length > this.config.PutThreshold)
            {
                ResumableUploader resumeUploader = new ResumableUploader(this.config);
                result = resumeUploader.UploadStream(stream, key, token, extra);
            }
            else
            {
                FormUploader formUploader = new FormUploader(this.config);
                result = formUploader.UploadStream(stream, key, token, extra);
            }

            return(result);
        }
示例#6
0
        /// <summary>
        /// 上传文件,根据文件大小以及设置的阈值(用户初始化UploadManager时可指定该值)自动选择:
        /// 若文件大小超过设定阈值,使用ResumableUploader,否则使用FormUploader
        /// </summary>
        /// <param name="localFile">本地待上传的文件名</param>
        /// <param name="key">要保存的文件名称</param>
        /// <param name="token">上传凭证</param>
        /// <param name="extra">上传可选设置</param>
        /// <returns>上传文件后的返回结果</returns>
        public HttpResult UploadFile(string localFile, string key, string token, PutExtra extra)
        {
            HttpResult result = new HttpResult();

            var fileInfo = IOUtils.Api.GetFileInfo(localFile);

            if (fileInfo.Size > this.config.PutThreshold)
            {
                ResumableUploader resumeUploader = new ResumableUploader(config);
                result = resumeUploader.UploadFile(localFile, key, token, extra);
            }
            else
            {
                FormUploader formUploader = new FormUploader(config);
                result = formUploader.UploadFile(localFile, key, token, extra);
            }

            return(result);
        }
示例#7
0
        /// <summary>
        /// 分片上传/断点续上传,带有自定义进度处理和上传控制,检查CRC32,可自动重试
        /// </summary>
        /// <param name="stream">待上传文件流</param>
        /// <param name="key">要保存的文件名称</param>
        /// <param name="upToken">上传凭证</param>
        /// <param name="putExtra">可选配置参数</param>
        /// <returns>上传文件后返回结果</returns>
        public HttpResult UploadStream(Stream stream, string key, string upToken, PutExtra putExtra)
        {
            HttpResult result = new HttpResult();

            //check put extra
            if (putExtra == null)
            {
                putExtra = new PutExtra();
            }
            if (putExtra.ProgressHandler == null)
            {
                putExtra.ProgressHandler = DefaultUploadProgressHandler;
            }
            if (putExtra.UploadController == null)
            {
                putExtra.UploadController = DefaultUploadController;
            }

            if (!(putExtra.BlockUploadThreads > 0 && putExtra.BlockUploadThreads <= 64))
            {
                putExtra.BlockUploadThreads = 1;
            }

            using (stream)
            {
                //start to upload
                try
                {
                    long uploadedBytes = 0;
                    long fileSize      = stream.Length;
                    long blockCount    = (fileSize + BLOCK_SIZE - 1) / BLOCK_SIZE;

                    //check resume record file
                    ResumeInfo resumeInfo = null;
                    if (IOUtils.Api.FileExist(putExtra.ResumeRecordFile))
                    {
                        resumeInfo = ResumeHelper.Load(putExtra.ResumeRecordFile);
                        if (resumeInfo != null && fileSize == resumeInfo.FileSize)
                        {
                            //check whether ctx expired
                            if (UnixTimestamp.IsContextExpired(resumeInfo.ExpiredAt))
                            {
                                resumeInfo = null;
                            }
                        }
                    }
                    if (resumeInfo == null)
                    {
                        resumeInfo = new ResumeInfo()
                        {
                            FileSize   = fileSize,
                            BlockCount = blockCount,
                            Contexts   = new string[blockCount],
                            ExpiredAt  = 0,
                        };
                    }

                    //calc upload progress
                    for (long blockIndex = 0; blockIndex < blockCount; blockIndex++)
                    {
                        string context = resumeInfo.Contexts[blockIndex];
                        if (!string.IsNullOrEmpty(context))
                        {
                            uploadedBytes += BLOCK_SIZE;
                        }
                    }

                    //set upload progress
                    putExtra.ProgressHandler(uploadedBytes, fileSize);

                    //init block upload error
                    //check not finished blocks to upload
                    UploadControllerAction        upCtrl            = putExtra.UploadController();
                    ManualResetEvent              manualResetEvent  = new ManualResetEvent(false);
                    Dictionary <long, byte[]>     blockDataDict     = new Dictionary <long, byte[]>();
                    Dictionary <long, HttpResult> blockMakeResults  = new Dictionary <long, HttpResult>();
                    Dictionary <string, long>     uploadedBytesDict = new Dictionary <string, long>();
                    uploadedBytesDict.Add("UploadProgress", uploadedBytes);
                    byte[] blockBuffer = new byte[BLOCK_SIZE];
                    for (long blockIndex = 0; blockIndex < blockCount; blockIndex++)
                    {
                        string context = resumeInfo.Contexts[blockIndex];
                        if (string.IsNullOrEmpty(context))
                        {
                            //check upload controller action before each chunk
                            while (true)
                            {
                                upCtrl = putExtra.UploadController();

                                if (upCtrl == UploadControllerAction.Aborted)
                                {
                                    result.Code     = (int)HttpCode.USER_CANCELED;
                                    result.RefCode  = (int)HttpCode.USER_CANCELED;
                                    result.RefText += string.Format("[{0}] [ResumableUpload] Info: upload task is aborted\n",
                                                                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                                    manualResetEvent.Set();
                                    return(result);
                                }
                                else if (upCtrl == UploadControllerAction.Suspended)
                                {
                                    result.RefCode  = (int)HttpCode.USER_PAUSED;
                                    result.RefText += string.Format("[{0}] [ResumableUpload] Info: upload task is paused\n",
                                                                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                                    manualResetEvent.WaitOne(1000);
                                }
                                else if (upCtrl == UploadControllerAction.Activated)
                                {
                                    break;
                                }
                            }

                            long offset = blockIndex * BLOCK_SIZE;
                            stream.Seek(offset, SeekOrigin.Begin);
                            int    blockLen  = stream.Read(blockBuffer, 0, BLOCK_SIZE);
                            byte[] blockData = new byte[blockLen];
                            Array.Copy(blockBuffer, blockData, blockLen);
                            blockDataDict.Add(blockIndex, blockData);

                            if (blockDataDict.Count == putExtra.BlockUploadThreads)
                            {
                                processMakeBlocks(blockDataDict, upToken, putExtra, resumeInfo, blockMakeResults, uploadedBytesDict, fileSize);
                                //check mkblk results
                                foreach (int blkIndex in blockMakeResults.Keys)
                                {
                                    HttpResult mkblkRet = blockMakeResults[blkIndex];
                                    if (mkblkRet.Code != 200)
                                    {
                                        result = mkblkRet;
                                        manualResetEvent.Set();
                                        return(result);
                                    }
                                }
                                blockDataDict.Clear();
                                blockMakeResults.Clear();
                                if (!string.IsNullOrEmpty(putExtra.ResumeRecordFile))
                                {
                                    ResumeHelper.Save(resumeInfo, putExtra.ResumeRecordFile);
                                }
                            }
                        }
                    }

                    if (blockDataDict.Count > 0)
                    {
                        processMakeBlocks(blockDataDict, upToken, putExtra, resumeInfo, blockMakeResults, uploadedBytesDict, fileSize);
                        //check mkblk results
                        foreach (int blkIndex in blockMakeResults.Keys)
                        {
                            HttpResult mkblkRet = blockMakeResults[blkIndex];
                            if (mkblkRet.Code != 200)
                            {
                                result = mkblkRet;
                                manualResetEvent.Set();
                                return(result);
                            }
                        }
                        blockDataDict.Clear();
                        blockMakeResults.Clear();
                        if (!string.IsNullOrEmpty(putExtra.ResumeRecordFile))
                        {
                            ResumeHelper.Save(resumeInfo, putExtra.ResumeRecordFile);
                        }
                    }

                    if (upCtrl == UploadControllerAction.Activated)
                    {
                        HttpResult hr = MakeFile(key, fileSize, key, upToken, putExtra, resumeInfo.Contexts);
                        if (hr.Code != (int)HttpCode.OK)
                        {
                            result.Shadow(hr);
                            result.RefText += string.Format("[{0}] [ResumableUpload] Error: mkfile: code = {1}, text = {2}\n",
                                                            DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), hr.Code, hr.Text);
                        }

                        if (IOUtils.Api.FileExist(putExtra.ResumeRecordFile))
                        {
                            IOUtils.Api.FileDelete(putExtra.ResumeRecordFile);
                        }
                        result.Shadow(hr);
                        result.RefText += string.Format("[{0}] [ResumableUpload] Uploaded: \"{1}\" ==> \"{2}\"\n",
                                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), putExtra.ResumeRecordFile, key);
                    }
                    else
                    {
                        result.Code     = (int)HttpCode.USER_CANCELED;
                        result.RefCode  = (int)HttpCode.USER_CANCELED;
                        result.RefText += string.Format("[{0}] [ResumableUpload] Info: upload task is aborted, mkfile\n",
                                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                    }

                    manualResetEvent.Set();
                    return(result);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.StackTrace);
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("[{0}] [ResumableUpload] Error: ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                    Exception e = ex;
                    while (e != null)
                    {
                        sb.Append(e.Message + " ");
                        e = e.InnerException;
                    }
                    sb.AppendLine();

                    result.RefCode  = (int)HttpCode.USER_UNDEF;
                    result.RefText += sb.ToString();
                }
            }

            return(result);
        }
示例#8
0
        /// <summary>
        /// 根据已上传的所有分片数据创建文件
        /// </summary>
        /// <param name="fileName">源文件名</param>
        /// <param name="size">文件大小</param>
        /// <param name="key">要保存的文件名</param>
        /// <param name="contexts">所有数据块的Context</param>
        /// <param name="upToken">上传凭证</param>
        /// <param name="putExtra">用户指定的额外参数</param>
        /// <returns>此操作执行后的返回结果</returns>
        private HttpResult MakeFile(string fileName, long size, string key, string upToken, PutExtra putExtra, string[] contexts)
        {
            HttpResult result = new HttpResult();

            try
            {
                string fnameStr    = "fname";
                string mimeTypeStr = "";
                string keyStr      = "";
                string paramStr    = "";
                //check file name
                if (!string.IsNullOrEmpty(fileName))
                {
                    fnameStr = string.Format("/fname/{0}", Base64.UrlSafeBase64Encode(fileName));
                }

                //check mime type
                if (!string.IsNullOrEmpty(putExtra.MimeType))
                {
                    mimeTypeStr = string.Format("/mimeType/{0}", Base64.UrlSafeBase64Encode(putExtra.MimeType));
                }

                //check key
                if (!string.IsNullOrEmpty(key))
                {
                    keyStr = string.Format("/key/{0}", Base64.UrlSafeBase64Encode(key));
                }

                //check extra params
                if (putExtra.Params != null && putExtra.Params.Count > 0)
                {
                    StringBuilder sb = new StringBuilder();
                    foreach (var kvp in putExtra.Params)
                    {
                        string k = kvp.Key;
                        string v = kvp.Value;
                        if (k.StartsWith("x:") && !string.IsNullOrEmpty(v))
                        {
                            sb.AppendFormat("/{0}/{1}", k, v);
                        }
                    }

                    paramStr = sb.ToString();
                }

                //get upload host
                string ak     = UpToken.GetAccessKeyFromUpToken(upToken);
                string bucket = UpToken.GetBucketFromUpToken(upToken);
                if (ak == null || bucket == null)
                {
                    return(HttpResult.InvalidToken);
                }

                string uploadHost = this.config.UpHost(ak, bucket);

                string url        = string.Format("{0}/mkfile/{1}{2}{3}{4}{5}", uploadHost, size, mimeTypeStr, fnameStr, keyStr, paramStr);
                string body       = string.Join(",", contexts);
                string upTokenStr = string.Format("UpToken {0}", upToken);

                result = httpManager.PostText(url, body, upTokenStr);
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("[{0}] mkfile Error: ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                Exception e = ex;
                while (e != null)
                {
                    sb.Append(e.Message + " ");
                    e = e.InnerException;
                }
                sb.AppendLine();

                if (ex is QiniuException)
                {
                    QiniuException qex = (QiniuException)ex;
                    result.Code     = qex.HttpResult.Code;
                    result.RefCode  = qex.HttpResult.Code;
                    result.Text     = qex.HttpResult.Text;
                    result.RefText += sb.ToString();
                }
                else
                {
                    result.RefCode  = (int)HttpCode.USER_UNDEF;
                    result.RefText += sb.ToString();
                }
            }

            return(result);
        }
示例#9
0
        /// <summary>
        /// 创建块(携带首片数据),同时检查CRC32
        /// </summary>
        /// <param name="resumeBlockerObj">创建分片上次的块请求</param>
        private void MakeBlock(object resumeBlockerObj)
        {
            ResumeBlocker    resumeBlocker = (ResumeBlocker)resumeBlockerObj;
            ManualResetEvent doneEvent     = resumeBlocker.DoneEvent;
            Dictionary <long, HttpResult> blockMakeResults = resumeBlocker.BlockMakeResults;
            PutExtra   putExtra   = resumeBlocker.PutExtra;
            long       blockIndex = resumeBlocker.BlockIndex;
            HttpResult result     = new HttpResult();

            //check whether to cancel
            while (true)
            {
                UploadControllerAction upCtl = resumeBlocker.PutExtra.UploadController();
                if (upCtl == UploadControllerAction.Suspended)
                {
                    doneEvent.WaitOne(1000);
                    continue;
                }
                else if (upCtl == UploadControllerAction.Aborted)
                {
                    doneEvent.Set();

                    result.Code     = (int)HttpCode.USER_CANCELED;
                    result.RefCode  = (int)HttpCode.USER_CANCELED;
                    result.RefText += string.Format("[{0}] [ResumableUpload] Info: upload task is aborted, mkblk {1}\n",
                                                    DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), blockIndex);
                    blockMakeResults.Add(blockIndex, result);
                    return;
                }
                else
                {
                    break;
                }
            }

            byte[] blockBuffer = resumeBlocker.BlockBuffer;
            int    blockSize   = blockBuffer.Length;

            string upToken = resumeBlocker.UploadToken;
            Dictionary <string, long> uploadedBytesDict = resumeBlocker.UploadedBytesDict;
            long       fileSize     = resumeBlocker.FileSize;
            object     progressLock = resumeBlocker.ProgressLock;
            ResumeInfo resumeInfo   = resumeBlocker.ResumeInfo;

            try
            {
                //get upload host
                string ak     = UpToken.GetAccessKeyFromUpToken(upToken);
                string bucket = UpToken.GetBucketFromUpToken(upToken);
                if (ak == null || bucket == null)
                {
                    result = HttpResult.InvalidToken;
                    doneEvent.Set();
                    return;
                }

                string uploadHost = this.config.UpHost(ak, bucket);

                string url        = string.Format("{0}/mkblk/{1}", uploadHost, blockSize);
                string upTokenStr = string.Format("UpToken {0}", upToken);
                using (MemoryStream ms = new MemoryStream(blockBuffer, 0, blockSize))
                {
                    byte[] data = ms.ToArray();

                    result = httpManager.PostData(url, data, upTokenStr);

                    if (result.Code == (int)HttpCode.OK)
                    {
                        ResumeContext rc = JsonConvert.DeserializeObject <ResumeContext>(result.Text);

                        if (rc.Crc32 > 0)
                        {
                            uint crc_1 = rc.Crc32;
                            uint crc_2 = CRC32.CheckSumSlice(blockBuffer, 0, blockSize);
                            if (crc_1 != crc_2)
                            {
                                result.RefCode  = (int)HttpCode.USER_NEED_RETRY;
                                result.RefText += string.Format(" CRC32: remote={0}, local={1}\n", crc_1, crc_2);
                            }
                            else
                            {
                                //write the mkblk context
                                resumeInfo.Contexts[blockIndex] = rc.Ctx;
                                resumeInfo.ExpiredAt            = rc.ExpiredAt;
                                lock (progressLock)
                                {
                                    uploadedBytesDict["UploadProgress"] += blockSize;
                                }
                                putExtra.ProgressHandler(uploadedBytesDict["UploadProgress"], fileSize);
                            }
                        }
                        else
                        {
                            result.RefText += string.Format("[{0}] JSON Decode Error: text = {1}",
                                                            DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), result.Text);
                            result.RefCode = (int)HttpCode.USER_NEED_RETRY;
                        }
                    }
                    else
                    {
                        result.RefCode = (int)HttpCode.USER_NEED_RETRY;
                    }
                }
            }
            catch (Exception ex)
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendFormat("[{0}] mkblk Error: ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                Exception e = ex;
                while (e != null)
                {
                    sb.Append(e.Message + " ");
                    e = e.InnerException;
                }
                sb.AppendLine();

                if (ex is QiniuException)
                {
                    QiniuException qex = (QiniuException)ex;
                    result.Code     = qex.HttpResult.Code;
                    result.RefCode  = qex.HttpResult.Code;
                    result.Text     = qex.HttpResult.Text;
                    result.RefText += sb.ToString();
                }
                else
                {
                    result.RefCode  = (int)HttpCode.USER_UNDEF;
                    result.RefText += sb.ToString();
                }
            }

            //return the http result
            blockMakeResults.Add(blockIndex, result);
            doneEvent.Set();
        }
示例#10
0
        /// <summary>
        /// 上传数据
        /// </summary>
        /// <param name="data">待上传的数据</param>
        /// <param name="key">要保存的文件名称</param>
        /// <param name="token">上传凭证</param>
        /// <param name="extra">上传可选设置</param>
        /// <returns>上传文件后的返回结果</returns>
        public HttpResult UploadData(byte[] data, string key, string token, PutExtra extra)
        {
            FormUploader formUploader = new FormUploader(this.config);

            return(formUploader.UploadData(data, key, token, extra));
        }
示例#11
0
        /// <summary>
        /// 上传数据流
        /// </summary>
        /// <param name="stream">(确定长度的)数据流</param>
        /// <param name="key">要保存的key</param>
        /// <param name="token">上传凭证</param>
        /// <param name="extra">上传可选设置</param>
        /// <returns>上传数据流后的返回结果</returns>
        public HttpResult UploadStream(Stream stream, string key, string token, PutExtra putExtra)
        {
            if (putExtra == null)
            {
                putExtra = new PutExtra();
            }
            if (string.IsNullOrEmpty(putExtra.MimeType))
            {
                putExtra.MimeType = "application/octet-stream";
            }
            if (putExtra.ProgressHandler == null)
            {
                putExtra.ProgressHandler = DefaultUploadProgressHandler;
            }
            if (putExtra.UploadController == null)
            {
                putExtra.UploadController = DefaultUploadController;
            }
            string fname = key;

            if (string.IsNullOrEmpty(key))
            {
                fname = "fname_temp";
            }

            HttpResult result = new HttpResult();

            using (stream)
            {
                try
                {
                    string        boundary    = HttpManager.CreateFormDataBoundary();
                    StringBuilder bodyBuilder = new StringBuilder();
                    bodyBuilder.AppendLine("--" + boundary);

                    if (key != null)
                    {
                        //write key when it is not null
                        bodyBuilder.AppendLine("Content-Disposition: form-data; name=\"key\"");
                        bodyBuilder.AppendLine();
                        bodyBuilder.AppendLine(key);
                        bodyBuilder.AppendLine("--" + boundary);
                    }

                    //write token
                    bodyBuilder.AppendLine("Content-Disposition: form-data; name=\"token\"");
                    bodyBuilder.AppendLine();
                    bodyBuilder.AppendLine(token);
                    bodyBuilder.AppendLine("--" + boundary);

                    //write extra params
                    if (putExtra.Params != null && putExtra.Params.Count > 0)
                    {
                        foreach (var p in putExtra.Params)
                        {
                            if (p.Key.StartsWith("x:"))
                            {
                                bodyBuilder.AppendFormat("Content-Disposition: form-data; name=\"{0}\"", p.Key);
                                bodyBuilder.AppendLine();
                                bodyBuilder.AppendLine();
                                bodyBuilder.AppendLine(p.Value);
                                bodyBuilder.AppendLine("--" + boundary);
                            }
                        }
                    }

                    //prepare data buffer
                    int    bufferSize = 1024 * 1024;
                    byte[] buffer     = new byte[bufferSize];
                    int    bytesRead  = 0;
                    putExtra.ProgressHandler(0, stream.Length);
                    MemoryStream dataMS = new MemoryStream();
                    while ((bytesRead = stream.Read(buffer, 0, bufferSize)) != 0)
                    {
                        dataMS.Write(buffer, 0, bytesRead);
                    }

                    //write crc32
                    uint crc32 = CRC32.CheckSumBytes(dataMS.ToArray());
                    //write key when it is not null
                    bodyBuilder.AppendLine("Content-Disposition: form-data; name=\"crc32\"");
                    bodyBuilder.AppendLine();
                    bodyBuilder.AppendLine(crc32.ToString());
                    bodyBuilder.AppendLine("--" + boundary);

                    //write fname
                    bodyBuilder.AppendFormat("Content-Disposition: form-data; name=\"file\"; filename=\"{0}\"", fname);
                    bodyBuilder.AppendLine();

                    //write mime type
                    bodyBuilder.AppendFormat("Content-Type: {0}", putExtra.MimeType);
                    bodyBuilder.AppendLine();
                    bodyBuilder.AppendLine();

                    //write file data
                    StringBuilder bodyEnd = new StringBuilder();
                    bodyEnd.AppendLine();
                    bodyEnd.AppendLine("--" + boundary + "--");

                    byte[] partData1 = Encoding.UTF8.GetBytes(bodyBuilder.ToString());
                    byte[] partData2 = dataMS.ToArray();
                    byte[] partData3 = Encoding.UTF8.GetBytes(bodyEnd.ToString());

                    MemoryStream ms = new MemoryStream();
                    ms.Write(partData1, 0, partData1.Length);
                    ms.Write(partData2, 0, partData2.Length);
                    ms.Write(partData3, 0, partData3.Length);

                    //get upload host
                    string ak     = UpToken.GetAccessKeyFromUpToken(token);
                    string bucket = UpToken.GetBucketFromUpToken(token);
                    if (ak == null || bucket == null)
                    {
                        return(HttpResult.InvalidToken);
                    }

                    string uploadHost = this.config.UpHost(ak, bucket);
                    putExtra.ProgressHandler(stream.Length / 5, stream.Length);
                    result = httpManager.PostMultipart(uploadHost, ms.ToArray(), boundary, null);
                    putExtra.ProgressHandler(stream.Length, stream.Length);
                    if (result.Code == (int)HttpCode.OK)
                    {
                        result.RefText += string.Format("[{0}] [FormUpload] Uploaded: #STREAM# ==> \"{1}\"\n",
                                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), key);
                    }
                    else
                    {
                        result.RefText += string.Format("[{0}] [FormUpload] Failed: code = {1}, text = {2}\n",
                                                        DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"), result.Code, result.Text);
                    }

                    //close memory stream
                    ms.Close();
                    dataMS.Close();
                }
                catch (Exception ex)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.AppendFormat("[{0}] [FormUpload] Error: ", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"));
                    Exception e = ex;
                    while (e != null)
                    {
                        sb.Append(e.Message + " ");
                        e = e.InnerException;
                    }
                    sb.AppendLine();

                    if (ex is QiniuException)
                    {
                        QiniuException qex = (QiniuException)ex;
                        result.Code     = qex.HttpResult.Code;
                        result.RefCode  = qex.HttpResult.Code;
                        result.Text     = qex.HttpResult.Text;
                        result.RefText += sb.ToString();
                    }
                    else
                    {
                        result.RefCode  = (int)HttpCode.USER_UNDEF;
                        result.RefText += sb.ToString();
                    }
                }
            }

            return(result);
        }
示例#12
0
        /// <summary>
        /// 上传数据
        /// </summary>
        /// <param name="data">待上传的数据</param>
        /// <param name="key">要保存的key</param>
        /// <param name="token">上传凭证</param>
        /// <param name="extra">上传可选设置</param>
        /// <returns>上传数据后的返回结果</returns>
        public HttpResult UploadData(byte[] data, string key, string token, PutExtra extra)
        {
            MemoryStream stream = new MemoryStream(data);

            return(this.UploadStream(stream, key, token, extra));
        }