public RequestStream(HttpWorkerRequest request) { this.request = request; tempBuff = request.GetPreloadedEntityBody(); _contentLength = long.Parse(request.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentLength)); // Handle the case where GetPreloadedEntityBody is null -- e.g. Mono if (tempBuff == null || tempBuff.Length == 0) { isInPreloaded = false; } }
public AsyncUpload(HttpWorkerRequest wRquest) { if (wRquest == null) throw new ArgumentNullException("wRquest"); this.uploadProcess = new UploadProcess(delegate(float f) { }); workerRequest = wRquest; //当前读到的流长度 this.preLen = workerRequest.GetPreloadedEntityBodyLength(); //请求流的总长度 this.totLen = workerRequest.GetTotalEntityBodyLength(); //内容分隔符 如: -----------------------------152733254716788 if (preLen == 0 && workerRequest.IsClientConnected() && workerRequest.HasEntityBody()) { byte[] buffer = new byte[8192]; preLen = workerRequest.ReadEntityBody(buffer, buffer.Length); byte[] buf = new byte[preLen]; for (int i = 0; i < buf.Length; i++) buf[i] = buffer[i]; this.perBodyBytes = buf; } else this.perBodyBytes = workerRequest.GetPreloadedEntityBody(); this.headerBytes = this.GetBoundaryBytes(Encoding.UTF8.GetBytes(workerRequest.GetKnownRequestHeader(HttpWorkerRequest.HeaderContentType))); //请求流尾部分隔符 如: -----------------------------152733254716788-- this.contentEnd = new byte[this.headerBytes.Length + 2]; this.headerBytes.CopyTo(this.contentEnd, 0); this.contentEnd[this.headerBytes.Length] = 45; this.contentEnd[this.headerBytes.Length + 1] = 45; //当前流中第一个文件分隔符的位置 int fHeaderPosition = perBodyBytes.Indexof(fileNameHeader); //尝试在已读取到的流中找文件尾位置 this.fEndPosition = perBodyBytes.Indexof(contentEnd); if (fHeaderPosition > -1) { //先找到文件名 IList<byte> bufList = new List<byte>(); int i = fHeaderPosition + fileNameHeader.Length; while (i < perBodyBytes.Length) { if (perBodyBytes[i] == 34) break; bufList.Add(perBodyBytes[i]); i++; } this.FileName = Encoding.UTF8.GetString(bufList.ToArray());//file name this.fPosition = perBodyBytes.Indexof(wrapBytes, i) + 4;//当前流中此文件的开始位置 this.FileLength = this.totLen - this.fPosition; } }
private void context_BeginRequest(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; HttpContext context = app.Context; // We need the HttpWorkerRequest of the current context to // process the request data. For more details about HttpWorkerRequest, // please follow the Readme file in the root directory. IServiceProvider provider = (IServiceProvider)context; System.Web.HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest)); // Get the content type of the current request. string contentType = request.GetKnownRequestHeader( System.Web.HttpWorkerRequest.HeaderContentType); // If we could not get the content type, then skip out the module if (contentType == null) { return; } // If the content type is not multipart/form-data, // means that there is no file upload request // then skip out the moudle if (contentType.IndexOf("multipart/form-data") == -1) { return; } string boundary = contentType.Substring(contentType.IndexOf("boundary=") + 9); // Get the content length of the current request long contentLength = Convert.ToInt64( request.GetKnownRequestHeader( HttpWorkerRequest.HeaderContentLength)); // Get the data of the portion of the HTTP request body // that has currently been read. // This is the first step for us to store the upload file. byte[] data = request.GetPreloadedEntityBody(); // Create an instance of the manager class which // help to filter the request data. FileUploadDataManager storeManager = new FileUploadDataManager(boundary); // Append the preloaded data. storeManager.AppendData(data); UploadStatus status = null; if (context.Cache[_cacheContainer] == null) { //Initialize the UploadStatus which used to //store the status for the client. status = new UploadStatus( context, // Send the current context to the status // which will be used for the events. contentLength // Initialize the file length. ); // Bind a event when update the status. status.OnDataChanged += new UploadStatusEventHandler(status_OnDataChanged); } else { status = context.Cache[_cacheContainer] as UploadStatus; if (status.IsFinished) { return; } } // Set the first read data length to the status class. if (data != null) { status.UpdateLoadedLength(data.Length); } // Get the length of the left request data. long leftdata = status.ContentLength - status.LoadedLength; // Define a custom buffer length int customBufferLength = Convert.ToInt32(Math.Ceiling((double)contentLength / 16)); if (customBufferLength < 1024) { customBufferLength = 1024; } while (!request.IsEntireEntityBodyIsPreloaded() && leftdata > 0) { // Check if user abort the upload, then close the connection if (status.Aborted) { // Delete the cached files. foreach (UploadFile file in storeManager.FilterResult) { file.ClearCache(); } request.CloseConnection(); return; } // If the length the remained request data // is less than the buffer length, // then set the buffer length as the remained data length. if (leftdata < customBufferLength) { customBufferLength = (int)leftdata; } // Read a custom buffer length of the request data data = new byte[customBufferLength]; int redlen = request.ReadEntityBody(data, customBufferLength); if (customBufferLength > redlen) { data = BinaryHelper.SubData(data, 0, redlen); } // Append the left data. storeManager.AppendData(data); // Add the buffer length to the status to update the upload status status.UpdateLoadedLength(redlen); leftdata -= redlen; } // After all the data has been read, // save the uploaded files. foreach (UploadFile file in storeManager.FilterResult) { file.Save(null); } }
/// <summary> /// Parses the request into files then parses the files into form fields and uploaded files. /// </summary> /// <param name="r">The r.</param> /// <returns></returns> Mapper ParseRequest(HttpWorkerRequest r) { // get the ID of the upload from the querystring if any var qid = r.GetQueryString(); Guid id; if(!Guid.TryParse(qid, out id)) { throw new HttpParseException("Upload contains no ID."); } var d = new HttpUploadStatusEventArgs() { Id = id, StartedOn = DateTime.Now, LastUpdated = DateTime.Now, Message = "Beginning Upload." }; var isIdFound = false; var isMapFound = false; var e = new UTF8Encoding(); // bytes for "Content-Disposition: form-data; " var mapSig = new byte[] { 67,111,110,116,101,110,116,45,68,105,115,112,111, 115,105,116,105,111,110,58,32,102,111,114,109, 45,100,97,116,97,59,32,110,97,109,101,61, 34,109,97,112,34,13,10,13,10 }; var idSig = new byte[] { 67,111,110,116,101,110,116,45,68,105,115,112,111,115,105,116,105, 111,110,58,32,102,111,114,109,45,100,97,116,97,59,32,110, 97,109,101,61,34,105,100,34,13,10,13,10}; var m = new Mapper(); // first 46 bytes = boundary signature const int f = 131072; // 128kb = 131072b var l = r.GetTotalEntityBodyLength(); d.BytesTotal = l; var p = r.GetPreloadedEntityBody(); var b = GetBoundary(p); updateUploadStatus(ref d,l,"Uploading preloaded entity body."); // load stream into temp file var fst = Path.GetTempFileName(); using (var fs = new FileStream(fst, FileMode.OpenOrCreate)) { // write preloaded body to file Debug.Assert(p != null, "GetPreloadedEntityBody != null"); fs.Write(p, 0, p.Length); var c = p.Length; var q = 0; var u = new byte[f]; updateUploadStatus(ref d, l, "Uploading."); while (l - c > q) { q = r.ReadEntityBody(u, 0, f); fs.Write(u, 0, q); c += q; updateUploadStatus(ref d, c, "Uploading."); } if (l - c > 0) { var ux = new byte[l - c]; q = r.ReadEntityBody(ux, 0, l - c); fs.Write(ux, 0, q); } fs.Flush(); fs.Position = 0; updateUploadStatus(ref d, c, "Upload Complete, Parsing upload."); // read the entire file finding all boundaries var s = new List<long>(); while (fs.Position < fs.Length) { s.Add(FindPosition(fs, b, fs.Position)); } fs.Position = 0; // the last boundary is the eof for (var i = 0; s.Count - 1 > i; i++) { // indexes between boundaries - this is the new file size in bytes if (s[i + 1] == -1) { break; } var z = s[i + 1] - s[i]; // this is the size of the object between the boundaries (including current boundary) var g = (z) < f ? z : f; // chunk size (g) = 131072 (f) or next boundary pos - current boundary pos (z) var n = Path.GetTempFileName(); fs.Position = s[i]; // start reading from the beginning position of the object (including boundary) using (var a = new FileStream(n, FileMode.OpenOrCreate)) { q = 0; c = 0; while (z - c > q) { //read blocks while position - mod block size is less than end position q = fs.Read(u, 0, (int)g); a.Write(u, 0, q); c += q; } q = fs.Read(u, 0, (int)z - c); a.Write(u, 0, q); a.Position = 0; // read in form data if (!isMapFound) { if (FindPosition(a, mapSig, 0) > -1) { // this is the map field var mapBytes = new byte[a.Length - a.Position - 2]; // -2 to drop the \r\n a.Read(mapBytes, 0, mapBytes.Length); m.Map = e.GetString(mapBytes); isMapFound = true; continue; } } if (!isIdFound) { if (FindPosition(a, idSig, 0) > -1) { // id is always 36 bytes var idBytes = new byte[36]; a.Read(idBytes, 0, 36); m.Id = Guid.Parse(e.GetString(idBytes)); isIdFound = true; continue; } } // this must be a binary file attachment, rip file apart a.Position = 0; //1) remove boundary while (a.ReadByte() != 13) { } a.Position++; // read past lf //2) parse form data var startOfFormData = a.Position; while (a.ReadByte() != 13) { } a.Position++; // read past lf var endOfFormdata = a.Position; a.Position = startOfFormData; // create a byte array to hold form data var formDataBuffer = new byte[endOfFormdata - startOfFormData]; a.Read(formDataBuffer, 0, formDataBuffer.Length); var formData = e.GetString(formDataBuffer); // form data looks like Content-Disposition: form-data; name="Authentication.CreateAccount_files_0_0"; filename="tiny.gif" //3) parse content type a.Position = endOfFormdata; while (a.ReadByte() != 13) { } a.Position++; // read past lf var endOfContentType = a.Position - 2; // -2 so we don't capture \r\n in content type string var contentTypeBuffer = new byte[endOfContentType - endOfFormdata]; a.Position = endOfFormdata; a.Read(contentTypeBuffer, 0, contentTypeBuffer.Length); var contentType = e.GetString(contentTypeBuffer); //4) remove extra \r\n\r\n a.Position = endOfContentType + 4; //5) the rest is the binary file // read it and store it in a new file var binLength = a.Length - a.Position; var bufferSize = f > binLength ? binLength : f; var remainingChunckSize = binLength % bufferSize; var bytesRead = 0L; var tempFileName = Path.GetTempFileName(); using (var bin = new FileStream(tempFileName, FileMode.OpenOrCreate)) { while (binLength - remainingChunckSize > bytesRead) { var buffer = new byte[bufferSize]; bytesRead += a.Read(buffer, 0, (int)bufferSize); bin.Write(buffer, 0, (int)bufferSize); } if (remainingChunckSize > 0) { var buffer = new byte[remainingChunckSize]; a.Read(buffer, 0, (int)remainingChunckSize); bin.Write(buffer, 0, (int)remainingChunckSize); } // make mapper ref var regex = new Regex(@".*name=""([^""]+)""; filename=""([^""]+)"""); var matches = regex.Match(formData); var methodSig = matches.Groups[1].Value; var oFileName = matches.Groups[2].Value; regex = new Regex(@"file:::(.*)_(\d)_files_(\d+)_(\d+)"); var matchesMetthod = regex.Match(methodSig); var method = matchesMetthod.Groups[1].Value; var methodInstance = matchesMetthod.Groups[2].Value; var fileField = matchesMetthod.Groups[3].Value; var fileNumber = matchesMetthod.Groups[4].Value; var fm = new UploadedFile { ContentType = contentType.Replace("Content-Type: ", ""), // remove the words "Content-Type: " from value Path = tempFileName, FileNumber = int.Parse(fileNumber), Instance = int.Parse(methodInstance), Method = method, FieldNumber = int.Parse(fileField), OriginalFileName = oFileName }; m.Files.Add(fm); } } // delete temp file File.Delete(n); } } File.Delete(fst); d.BytesTotal = 0; d.BytesRead = 0; d.Complete = true; d.LastUpdated = DateTime.Now; d.Message = "Upload Complete."; RaiseOnUploadStatus(d); return m; }
private void context_BeginRequest(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; HttpContext context = app.Context; // 我们需要HttpWorkerRequest的当前内容来处理请求数据. // 要想知道HttpWorkerRequest更多更详细的内容, // 请参考根目录下的Readme文件. IServiceProvider provider = (IServiceProvider)context; System.Web.HttpWorkerRequest request = (HttpWorkerRequest)provider.GetService(typeof(HttpWorkerRequest)); // 获取当前请求的内容类型. string contentType = request.GetKnownRequestHeader( System.Web.HttpWorkerRequest.HeaderContentType); // 如果我们不能获取内容类型,跳过这个模块. if (contentType == null) { return; } // 如果内容类型不是multipart/form-data, // 意味着没有上传请求, // 就可以跳过这个模块. if (contentType.IndexOf("multipart/form-data") == -1) { return; } string boundary = contentType.Substring(contentType.IndexOf("boundary=") + 9); // 获取当前请求的内容长度. long contentLength = Convert.ToInt64( request.GetKnownRequestHeader( HttpWorkerRequest.HeaderContentLength)); // 获取HTTP请求主体的那些 // 当前已经被读取的数据. // 这是我们存储上传文件的第一步. byte[] data = request.GetPreloadedEntityBody(); // 创建一个管理类的实例可以 // 帮助过滤请求数据. FileUploadDataManager storeManager = new FileUploadDataManager(boundary); // 添加预装载的数据. storeManager.AppendData(data); UploadStatus status = null; if (context.Cache[_cacheContainer] == null) { //初始化UploadStatus, //它被用来存储客户状态. status = new UploadStatus( context, // 把当前内容发送到status被事件使用 // contentLength // 初始化文件长度. ); // 当更新状态时绑定事件. status.OnDataChanged += new UploadStatusEventHandler(status_OnDataChanged); } else { status = context.Cache[_cacheContainer] as UploadStatus; if (status.IsFinished) { return; } } // 把首先读到的数据长度设置到status class. if (data != null) { status.UpdateLoadedLength(data.Length); } // 获取留下的请求数据的长度. long leftdata = status.ContentLength - status.LoadedLength; // 定义一个自定义的缓存区的长度 int customBufferLength = Convert.ToInt32(Math.Ceiling((double)contentLength / 16)); if (customBufferLength < 1024) { customBufferLength = 1024; } while (!request.IsEntireEntityBodyIsPreloaded() && leftdata > 0) { // 检查用户如果终止了上传,关闭连接. if (status.Aborted) { // 删除缓存文件. foreach (UploadFile file in storeManager.FilterResult) { file.ClearCache(); } request.CloseConnection(); return; } // 如果剩下的请求数据小于缓 // 冲区的长度,把缓冲区的 // 长度设置成剩余数据的长度. if (leftdata < customBufferLength) { customBufferLength = (int)leftdata; } // 读取自定义缓冲区的长度的请求数据 data = new byte[customBufferLength]; int redlen = request.ReadEntityBody(data, customBufferLength); if (customBufferLength > redlen) { data = BinaryHelper.SubData(data, 0, redlen); } // 添加剩余数据. storeManager.AppendData(data); // 把缓冲区的长度添加到status来更新上传status. status.UpdateLoadedLength(redlen); leftdata -= redlen; } // 当所有的数据都被读取之后, // 保存上传文件. foreach (UploadFile file in storeManager.FilterResult) { file.Save(null); } }