/// <summary> /// 初始化上传任务 /// </summary> /// <param name="upToken">上传凭证</param> /// <param name="encodedObjectName">Base64编码后的资源名</param> /// <returns>此操作执行后的返回结果</returns> private HttpResult initReq(string encodedObjectName, string upToken) { HttpResult result = new HttpResult(); try { 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}/buckets/{1}/objects/{2}/uploads", uploadHost, bucket, encodedObjectName); string upTokenStr = string.Format("UpToken {0}", upToken); result = httpManager.PostText(url, null, 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); }
/// <summary> /// 上传数据片,同时检查CRC32 /// </summary> /// <param name="chunkBuffer">数据片</param> /// <param name="offset">当前片在块中的偏移位置</param> /// <param name="chunkSize">当前片的大小</param> /// <param name="context">承接前一片数据用到的Context</param> /// <param name="upToken">上传凭证</param> /// <returns>此操作执行后的返回结果</returns> private HttpResult BputChunk(byte[] chunkBuffer, long offset, long chunkSize, string context, string upToken) { HttpResult result = new HttpResult(); try { //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}/bput/{1}/{2}", uploadHost, context, offset); string upTokenStr = string.Format("UpToken {0}", upToken); using (MemoryStream ms = new MemoryStream(chunkBuffer, 0, (int)chunkSize)) { byte[] data = ms.ToArray(); result = httpManager.PostData(url, data, upTokenStr); if (result.Code == (int)HttpCode.OK) { Dictionary <string, string> rd = JsonConvert.DeserializeObject <Dictionary <string, string> >(result.Text); if (rd.ContainsKey("crc32")) { uint crc_1 = Convert.ToUInt32(rd["crc32"]); uint crc_2 = CRC32.CheckSumSlice(chunkBuffer, 0, (int)chunkSize); 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 { 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}] bput 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); }
/// <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); }
/// <summary> /// 上传数据流 /// </summary> /// <param name="stream">(确定长度的)数据流</param> /// <param name="key">要保存的key</param> /// <param name="token">上传凭证</param> /// <param name="putExtra">上传可选设置</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(); 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(); } } finally { if (stream != null) { try { stream.Close(); stream.Dispose(); } catch (Exception) { } } } return(result); }
/// <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(); }
/// <summary> /// 根据已上传的所有分片数据创建文件 /// </summary> /// <param name="fileName">源文件名</param> /// <param name="resumeInfo">分片上传记录信息</param> /// <param name="key">要保存的文件名</param> /// <param name="upToken">上传凭证</param> /// <param name="putExtra">用户指定的额外参数</param> /// <param name="encodedObjectName">Base64编码后的资源名</param> /// <returns>此操作执行后的返回结果</returns> private HttpResult completeParts(string fileName, ResumeInfo resumeInfo, string key, string upToken, PutExtra putExtra, string encodedObjectName) { HttpResult result = new HttpResult(); try { string paramStr = "{}"; if (string.IsNullOrEmpty(fileName)) { fileName = "fname"; } if (string.IsNullOrEmpty(putExtra.MimeType)) { putExtra.MimeType = ""; } if (string.IsNullOrEmpty(key)) { key = ""; } if (putExtra.Params != null) { paramStr = JsonConvert.SerializeObject(putExtra.Params); } //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 upTokenStr = string.Format("UpToken {0}", upToken); Dictionary <string, object> body = new Dictionary <string, object>(); body.Add("fname", fileName); body.Add("mimeType", putExtra.MimeType); body.Add("customVars", null); body.Add("parts", resumeInfo.Etags); string url = string.Format("{0}/buckets/{1}/objects/{2}/uploads/{3}", uploadHost, bucket, encodedObjectName, resumeInfo.UploadId); string bodyStr = JsonConvert.SerializeObject(body); result = httpManager.PostJson(url, bodyStr, upTokenStr); } catch (Exception ex) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("[{0}] completeParts 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); }