public static FileHeaderInfo ParseHeaderInfo(byte[] bytes, Encoding encoding) { var data = Parse(bytes, encoding); FileHeaderInfo result = null; foreach(var s in data.Boundaries) { if(s.Contains("Content-Disposition")) { var nameMatch = new Regex(@"(?<=name\=\"")(.*?)(?=\"")").Match(s); var fileNameMatch = new Regex(@"(?<=filename\=\"")(.*?)(?=\"")").Match(s); if(nameMatch.Success && fileNameMatch.Success && nameMatch.Value == "act-file-data") { // Look for Content-Type var re = new Regex(@"(?<=Content\-Type:)(.*?)(?=" + EOF + EOF + ")"); var contentTypeMatch = re.Match(data.Source); if(!contentTypeMatch.Success) return null; // Find start index position of file contents. That should be 2 lines after Content Type. var startIndexOld = contentTypeMatch.Index + contentTypeMatch.Length + (EOF + EOF).Length; var startIndex = GetContentTypeIndex(bytes, encoding, contentTypeMatch.Value) + contentTypeMatch.Length + (EOF + EOF).Length; result = new FileHeaderInfo { StartIndex = startIndex, BoundaryDelimiterLength = (EOF + data.Delimiter + EOF + EOF).Length, //endIndex - startIndex, FileName = fileNameMatch.Value.Trim(), ContentType = contentTypeMatch.Value.Trim() }; } } } return result; }
public static bool ProcessStream(HttpContext context, Stream source, string fileId, string fileName, bool chunked, bool isFirstChunk, bool usePoll) { FileHeaderInfo headerInfo = null; Stream destination = null; var states = new AjaxFileUploadStates(context, fileId); using (var tmpStream = new MemoryStream()) { var totalBytesRead = 0; var done = false; var fileLength = 0; while (true) { if (states.Abort) { return(false); } // read per chunk var chunkSize = usePoll ? ChunkSizeForPolling : ChunkSize; if (chunkSize > source.Length) { chunkSize = (int)source.Length; if (usePoll) { states.FileLength = chunkSize; } } var chunk = new byte[chunkSize]; var index = 0; while (index < chunk.Length) { var bytesRead = source.Read(chunk, index, chunk.Length - index); if (bytesRead == 0) { break; } if (usePoll) { states.Uploaded += bytesRead; } index += bytesRead; } totalBytesRead += index; // Byte is not empty nor reach end of file if (index != 0) { // Keep seeking header info until it's found if (headerInfo == null) { // Append every first byte into temporary memory stream tmpStream.Write(chunk, 0, index); // Load it all into byte array, and try parse it so we can get header info var firstBytes = tmpStream.ToArray(); // Find header info from first bytes. headerInfo = MultipartFormDataParser.ParseHeaderInfo(firstBytes, Encoding.UTF8); // If it's found, then start writing to file. if (headerInfo != null) { // Calculate total file length. fileLength = ((int)(source.Length - headerInfo.BoundaryDelimiterLength) - headerInfo.StartIndex); if (usePoll) { states.FileLength = fileLength; } // Only write file data, so not all bytes are written. var lengthToWrite = totalBytesRead - headerInfo.StartIndex; if (lengthToWrite > fileLength) { lengthToWrite = fileLength; done = true; } // Get first chunk of file data. var firstChunk = new byte[lengthToWrite]; Buffer.BlockCopy(firstBytes, headerInfo.StartIndex, firstChunk, 0, lengthToWrite); // Prepare temporary folder, we use file id as a folder name. var tempFolder = AjaxFileUpload.BuildTempFolder(fileId); if (!Directory.Exists(tempFolder)) { Directory.CreateDirectory(tempFolder); } // Build temporary file path. var tmpFilePath = Path.Combine(tempFolder, fileName); if (!IsSubDirectory(AjaxFileUpload.BuildRootTempFolder(), Path.GetDirectoryName(tmpFilePath))) { throw new Exception("Insecure operation prevented"); } if (!chunked || isFirstChunk) { // Create new file, if this is a first chunk or file is not chunked. destination = new FileStream(tmpFilePath, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite); } else { // Append data to existing teporary file for next chunks destination = new FileStream(tmpFilePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite); } // Writing it now. destination.Write(firstChunk, 0, lengthToWrite); } } else { var length = index; // Reach in the end of stream, remove last boundary if (destination.Length + index > fileLength) { length -= headerInfo.BoundaryDelimiterLength; done = true; } destination.Write(chunk, 0, length); } } // There is no byte to read anymore, upload is finished. if (done || index != chunk.Length) { if (destination != null) { destination.Close(); destination.Dispose(); } break; } } } return(true); }
internal static bool ProcessStream(HttpContext context, Stream source, string fileId, string fileName, bool chunked, bool isFirstChunk, bool usePoll, string azureContainerName) { if (string.IsNullOrEmpty(azureContainerName)) { throw new Exception("AzureContainerName is not specified."); } FileHeaderInfo headerInfo = null; var states = new AjaxFileUploadStates(context, fileId); var uploaded = 0; using (var tmpStream = new MemoryStream()) { var totalBytesRead = 0; var done = false; var fileLength = 0; var blobClient = GetCloudBlobClient(); var blobContainer = blobClient.GetContainerReference(azureContainerName); blobContainer.CreateIfNotExists(); CloudBlockBlob blob = null; while (true) { if (states.Abort) { return(false); } // read per chunk var chunkSize = usePoll ? ChunkSizeForPolling : ChunkSize; if (chunkSize > source.Length) { chunkSize = (int)source.Length; if (usePoll) { states.FileLength = chunkSize; } } var chunk = new byte[chunkSize]; var index = 0; while (index < chunk.Length) { var bytesRead = source.Read(chunk, index, chunk.Length - index); if (bytesRead == 0) { break; } if (usePoll) { states.Uploaded += bytesRead; } index += bytesRead; } totalBytesRead += index; // Byte is not empty nor reach end of file if (index != 0) { // Keep seeking header info until it's found if (headerInfo == null) { // Append every first byte into temporary memory stream tmpStream.Write(chunk, 0, index); // Load it all into byte array, and try parse it so we can get header info var firstBytes = tmpStream.ToArray(); // Find header info from first bytes. headerInfo = MultipartFormDataParser.ParseHeaderInfo(firstBytes, Encoding.UTF8); // If it's found, then start writing to file. if (headerInfo != null) { // Calculate total file length. fileLength = ((int)(source.Length - headerInfo.BoundaryDelimiterLength) - headerInfo.StartIndex); if (usePoll) { states.FileLength = fileLength; } // Only write file data, so not all bytes are written. var lengthToWrite = totalBytesRead - headerInfo.StartIndex; if (lengthToWrite > fileLength) { lengthToWrite = fileLength; done = true; } // Get first chunk of file data. var firstChunk = new byte[lengthToWrite]; Buffer.BlockCopy(firstBytes, headerInfo.StartIndex, firstChunk, 0, lengthToWrite); // Create blob reference. blob = blobContainer.GetBlockBlobReference(fileName); if (!chunked || isFirstChunk) { blob.DeleteIfExists(); } var id = Convert.ToBase64String(Guid.NewGuid().ToByteArray()); blob.PutBlock(id, new MemoryStream(firstChunk, true), null); uploaded = firstChunk.Length; states.BlockList.Add(id); } } else { var length = index; // Reach in the end of stream, remove last boundary if (uploaded + index > fileLength) { length -= headerInfo.BoundaryDelimiterLength; done = true; } var id = Convert.ToBase64String(Guid.NewGuid().ToByteArray()); blob.PutBlock(id, new MemoryStream(chunk, 0, length, true), null); uploaded += length; states.BlockList.Add(id); } } // There is no byte to read anymore, upload is finished. if (done || index != chunk.Length) { if (blob != null) { blob.PutBlockList(states.BlockList); states.AzureBlobUri = blob.Uri.AbsoluteUri; } break; } } } return(true); }