// 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; } } }
// 过滤请求数据来获取文件的二进制数据. // 这里是过滤数据的算法逻辑. // 在我们讲到算法之前将会有很多内容要 // 讲(可能要一本书).所以我只在这里开 // 个头,但是忽略详细的解释. 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; } } }