Exemplo n.º 1
0
        // Filter the request data to get the file binary data.
        // Here is an algorithm logic to filter the data. There
        // will be a lot of words to say before we talk about
        // the algorithm(Maybe a small book). So I just open the
        // source here but omit the explanation in details.
        private void FilterFileDataFromBodyEntity(byte[] data)
        {
            if (data == null)
            {
                return;
            }

            if (draft != null)
            {
                byte[] temp = BinaryHelper.Combine(draft,
                                                   BinaryHelper.Copy(data, 0, _boundary.Length));
                int entity_st = BinaryHelper.SequenceIndexOf(temp, _boundary, 0);
                int entity_ed = BinaryHelper.SequenceIndexOf(temp, _boundary,
                                                             entity_st + _boundary.Length + 2);

                if (isFile && !isFinished)
                {
                    if (entity_st == 0)
                    {
                        int header_st = entity_st + _boundary.Length + 2;
                        int header_ed = BinaryHelper.SequenceIndexOf(temp,
                                                                     _doubleBackSpace, header_st);
                        int body_st = header_ed + 4;
                        if (entity_ed == -1)
                        {
                            AppendToLastEntity(BinaryHelper.SubData(draft, body_st));
                            draft = null;
                        }
                        else
                        {
                            AppendToLastEntity(BinaryHelper.SubData(draft,
                                                                    body_st, entity_ed - body_st - 2));
                            isFinished = true;
                            isFile     = false;
                            draft      = BinaryHelper.SubData(draft, entity_ed);
                        }
                    }
                    else
                    {
                        AppendToLastEntity(draft);
                        draft = null;
                    }
                }

                // When need append new data, combine the two
                // binary array into one.
                data  = BinaryHelper.Combine(draft, data);
                draft = null;
            }
            while (true)
            {
                // find the boundary
                int entity_st = BinaryHelper.SequenceIndexOf(data, _boundary, 0);

                // if the current loaded data contain the boundary
                if (entity_st > -1)
                {
                    if (isFile && !isFinished)
                    {
                        AppendToLastEntity(BinaryHelper.SubData(data, 0,
                                                                entity_st - 2));
                        data       = BinaryHelper.SubData(data, entity_st);
                        isFile     = false;
                        isFinished = true;
                        continue;
                    }

                    int entity_ed = BinaryHelper.SequenceIndexOf(data, _boundary,
                                                                 entity_st + _boundary.Length + 2);
                    int header_st = entity_st + _boundary.Length + 2;
                    int header_ed = BinaryHelper.SequenceIndexOf(data,
                                                                 _doubleBackSpace, header_st);
                    int body_st = header_ed + 4;

                    if (body_st < 4)
                    {
                        // If the header in the entity is not complete, then
                        // set the draft as the data, and dump out the function
                        // to ask for more data.
                        draft = data;
                        return;
                    }
                    else
                    {
                        // If the header in the entity is complete
                        if (!isFile && isFinished)
                        {
                            // Encoding the data in the header of the entity
                            string headerInEntity = ASCIIEncoding.UTF8.GetString(
                                BinaryHelper.SubData(data, header_st, header_ed - header_st));
                            // If it is a file entity, the header contain the keyword:"filename".
                            if (headerInEntity.IndexOf("filename") > -1)
                            {
                                // Use Regular Expression to get the meta key values from
                                // the header of the entity.
                                Regex detailsReg =
                                    new Regex("Content-Disposition: form-data; name=\"([^\"]*)\";" +
                                              " filename=\"([^\"]*)\"Content-Type: ([^\"]*)");
                                Match regMatch =
                                    detailsReg.Match(headerInEntity.Replace("\r\n", ""));
                                string controlName = regMatch.Groups[1].Value;
                                string clientPath  = regMatch.Groups[2].Value;
                                string contentType = regMatch.Groups[3].Value;
                                if (string.IsNullOrEmpty(clientPath))
                                {
                                    isFile = false;
                                }
                                else
                                {
                                    isFile = true;
                                    // Create a new instance for the file entity
                                    UploadFile up = new UploadFile(clientPath, contentType);
                                    FilterResult.Add(up);
                                    isFinished = false;
                                }
                            }
                            else
                            {
                                isFile = false;
                            }
                        }
                    }
                    if (entity_ed > -1)
                    {
                        // If we can find another boundary after the first boundary,
                        // that means the entity block is ended there.
                        // Only if it is a file entity we need to get the data
                        // in the body of the entity
                        if (isFile)
                        {
                            AppendToLastEntity(BinaryHelper.SubData(data,
                                                                    body_st, entity_ed - body_st - 2));
                            isFinished = true;
                            isFile     = false;
                        }
                        // Remove the current processed entity data
                        // and loop for the next one.
                        data = BinaryHelper.SubData(data, entity_ed);
                        if (BinaryHelper.Equals(data, _endTag))
                        {
                            data  = null;
                            draft = null;
                            return;
                        }
                        continue;
                    }
                    else
                    {
                        // If we can't find the end mark, we have to
                        // move the data to the draft and
                        // ask for new data to append.
                        draft = data;
                        return;
                    }
                }
                else
                {
                    // If we can't find any mark of the boundary,
                    // we have to move the data to the draft and
                    // ask for new data to append.
                    draft = data;
                    return;
                }
            }
        }
Exemplo n.º 2
0
        // 过滤请求数据来获取文件的二进制数据.
        // 这里是过滤数据的算法逻辑.
        // 在我们讲到算法之前将会有很多内容要
        // 讲(可能要一本书).所以我只在这里开
        // 个头,但是忽略详细的解释.
        private void FilterFileDataFromBodyEntity(byte[] data)
        {
            if (data == null)
            {
                return;
            }

            if (draft != null)
            {
                byte[] temp = BinaryHelper.Combine(draft,
                                                   BinaryHelper.Copy(data, 0, _boundary.Length));
                int entity_st = BinaryHelper.SequenceIndexOf(temp, _boundary, 0);
                int entity_ed = BinaryHelper.SequenceIndexOf(temp, _boundary,
                                                             entity_st + _boundary.Length + 2);

                if (isFile && !isFinished)
                {
                    if (entity_st == 0)
                    {
                        int header_st = entity_st + _boundary.Length + 2;
                        int header_ed = BinaryHelper.SequenceIndexOf(temp,
                                                                     _doubleBackSpace, header_st);
                        int body_st = header_ed + 4;
                        if (entity_ed == -1)
                        {
                            AppendToLastEntity(BinaryHelper.SubData(draft, body_st));
                            draft = null;
                        }
                        else
                        {
                            AppendToLastEntity(BinaryHelper.SubData(draft,
                                                                    body_st, entity_ed - body_st - 2));
                            isFinished = true;
                            isFile     = false;
                            draft      = BinaryHelper.SubData(draft, entity_ed);
                        }
                    }
                    else
                    {
                        AppendToLastEntity(draft);
                        draft = null;
                    }
                }

                // 当需要添加新数据时,
                // 把这两个二进制数组合并成一个.
                data  = BinaryHelper.Combine(draft, data);
                draft = null;
            }
            while (true)
            {
                // 找到边界
                int entity_st = BinaryHelper.SequenceIndexOf(data, _boundary, 0);

                // 如果当前加载的数据包含边界
                if (entity_st > -1)
                {
                    if (isFile && !isFinished)
                    {
                        AppendToLastEntity(BinaryHelper.SubData(data, 0,
                                                                entity_st - 2));
                        data       = BinaryHelper.SubData(data, entity_st);
                        isFile     = false;
                        isFinished = true;
                        continue;
                    }

                    int entity_ed = BinaryHelper.SequenceIndexOf(data, _boundary,
                                                                 entity_st + _boundary.Length + 2);
                    int header_st = entity_st + _boundary.Length + 2;
                    int header_ed = BinaryHelper.SequenceIndexOf(data,
                                                                 _doubleBackSpace, header_st);
                    int body_st = header_ed + 4;

                    if (body_st < 4)
                    {
                        // 如果实体的头部不完整,
                        // 设置这个实体作为数据,
                        // 卸载掉函数来请求更多的数据.
                        draft = data;
                        return;
                    }
                    else
                    {
                        // 如果实体的头部完整
                        if (!isFile && isFinished)
                        {
                            // 把实体头部的数据转换为UTF8编码
                            string headerInEntity = ASCIIEncoding.UTF8.GetString(
                                BinaryHelper.SubData(data, header_st, header_ed - header_st));
                            // 如果这是一个文件实体,头部包会含关键字:"filename".
                            if (headerInEntity.IndexOf("filename") > -1)
                            {
                                // 在实体的头部使用正则表达式来
                                // 获取元数据的关键字值.
                                Regex detailsReg =
                                    new Regex("Content-Disposition: form-data; name=\"([^\"]*)\";" +
                                              " filename=\"([^\"]*)\"Content-Type: ([^\"]*)");
                                Match regMatch =
                                    detailsReg.Match(headerInEntity.Replace("\r\n", ""));
                                string controlName = regMatch.Groups[1].Value;
                                string clientPath  = regMatch.Groups[2].Value;
                                string contentType = regMatch.Groups[3].Value;
                                if (string.IsNullOrEmpty(clientPath))
                                {
                                    isFile = false;
                                }
                                else
                                {
                                    isFile = true;
                                    // 为文件实体创建一个新的实例
                                    UploadFile up = new UploadFile(clientPath, contentType);
                                    FilterResult.Add(up);
                                    isFinished = false;
                                }
                            }
                            else
                            {
                                isFile = false;
                            }
                        }
                    }
                    if (entity_ed > -1)
                    {
                        // 如果我们在第一个边界之后又发现另一边界,
                        // 那表示实体块在那里结束了.
                        // 只是文件实体的时候,我们才需要在实体的
                        // 主体里获取数据.
                        if (isFile)
                        {
                            AppendToLastEntity(BinaryHelper.SubData(data,
                                                                    body_st, entity_ed - body_st - 2));
                            isFinished = true;
                            isFile     = false;
                        }
                        // 移除当前的实体处理数据并且
                        // 循环到下一个数据.
                        data = BinaryHelper.SubData(data, entity_ed);
                        if (BinaryHelper.Equals(data, _endTag))
                        {
                            data  = null;
                            draft = null;
                            return;
                        }
                        continue;
                    }
                    else
                    {
                        // 如果我们不能找到结束标记,我们
                        // 必须要把这些数据移到草稿并
                        // 请求添加新数据.
                        draft = data;
                        return;
                    }
                }
                else
                {
                    // 如果我们不能找到结束标记,我们
                    // 必须要把这些数据移到草稿并
                    // 请求添加新数据.
                    draft = data;
                    return;
                }
            }
        }
Exemplo n.º 3
0
        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);
            }
        }
Exemplo n.º 4
0
        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);
            }
        }