Esempio n. 1
0
        /// <summary>
        /// Parses a section of the stream that is known to be file data.
        /// </summary>
        /// <param name="parameters">
        /// The header parameters of this file, expects "name" and "filename" to be valid keys
        /// </param>
        /// <param name="reader">
        /// The StreamReader to read the data from
        /// </param>
        /// <returns>
        /// The <see cref="FilePart"/> containing the parsed data (name, filename, stream containing file).
        /// </returns>
        private HttpFile ParseFilePart(Dictionary <string, string> parameters, RebufferableBinaryReader reader)
        {
            // We want to create a stream and fill it with the data from the
            // file.

            var temp = Security.TempFile;

            using (var data = new FileStream(temp, FileMode.OpenOrCreate))
            {
                var curBuffer  = new byte[BinaryBufferSize];
                var prevBuffer = new byte[BinaryBufferSize];
                int curLength  = 0;
                int prevLength = 0;

                prevLength = reader.Read(prevBuffer, 0, prevBuffer.Length);
                do
                {
                    curLength = reader.Read(curBuffer, 0, curBuffer.Length);

                    // Combine both buffers into the fullBuffer
                    // See: http://stackoverflow.com/questions/415291/best-way-to-combine-two-or-more-byte-arrays-in-c-sharp
                    var fullBuffer = new byte[BinaryBufferSize * 2];
                    Buffer.BlockCopy(prevBuffer, 0, fullBuffer, 0, prevLength);
                    Buffer.BlockCopy(curBuffer, 0, fullBuffer, prevLength, curLength);

                    // Now we want to check for a substring within the current buffer.
                    // We need to find the closest substring greedily. That is find the
                    // closest boundary and don't miss the end --'s if it's an end boundary.
                    int endBoundaryPos    = SubsequenceFinder.Search(fullBuffer, this.endBoundaryBinary);
                    int endBoundaryLength = this.endBoundaryBinary.Length;
                    int boundaryPos       = SubsequenceFinder.Search(fullBuffer, this.boundaryBinary);
                    int boundaryLength    = this.boundaryBinary.Length;

                    // We need to select the appropriate position and length
                    // based on the smallest non-negative position.
                    int endPos       = -1;
                    int endPosLength = 0;

                    if (endBoundaryPos >= 0 && boundaryPos >= 0)
                    {
                        if (boundaryPos < endBoundaryPos)
                        {
                            // Select boundary
                            endPos       = boundaryPos;
                            endPosLength = boundaryLength;
                        }
                        else
                        {
                            // Select end boundary
                            endPos               = endBoundaryPos;
                            endPosLength         = endBoundaryLength;
                            this.readEndBoundary = true;
                        }
                    }
                    else if (boundaryPos >= 0 && endBoundaryPos < 0)
                    {
                        // Select boundary
                        endPos       = boundaryPos;
                        endPosLength = boundaryLength;
                    }
                    else if (boundaryPos < 0 && endBoundaryPos >= 0)
                    {
                        // Select end boundary
                        endPos               = endBoundaryPos;
                        endPosLength         = endBoundaryLength;
                        this.readEndBoundary = true;
                    }

                    if (endPos != -1)
                    {
                        // Now we need to check if the endPos is followed by \r\n or just \n. HTTP
                        // specifies \r\n but some clients might encode with \n. Or we might get 0 if
                        // we are at the end of the file.
                        int boundaryNewlineOffset = CalculateNewlineLength(ref fullBuffer, endPos + endPosLength);

                        // We also need to check if the last n characters of the buffer to write
                        // are a newline and if they are ignore them.
                        var maxNewlineBytes     = Encoding.GetMaxByteCount(2);
                        int bufferNewlineOffset = this.FindNextNewline(ref fullBuffer, Math.Max(0, endPos - maxNewlineBytes), maxNewlineBytes);
                        int bufferNewlineLength = this.CalculateNewlineLength(ref fullBuffer, bufferNewlineOffset);

                        // We've found an end. We need to consume all the binary up to it
                        // and then write the remainder back to the original stream. Then we
                        // need to modify the original streams position to take into account
                        // the new data.
                        // We also want to chop off the newline that is inserted by the protocl.
                        // We can do this by reducing endPos by the length of newline in this environment
                        // and encoding
                        data.Write(fullBuffer, 0, endPos - bufferNewlineLength);

                        int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset;
                        int writeBackAmount = (prevLength + curLength) - writeBackOffset;
                        var writeBackBuffer = new byte[writeBackAmount];
                        Buffer.BlockCopy(fullBuffer, writeBackOffset, writeBackBuffer, 0, writeBackAmount);
                        reader.Buffer(writeBackBuffer);

                        // stream.Write(fullBuffer, writeBackOffset, writeBackAmount);
                        // stream.Position = stream.Position - writeBackAmount;
                        // stream.Flush();
                        data.Position = 0;
                        data.Flush();
                        break;
                    }

                    // No end, consume the entire previous buffer
                    data.Write(prevBuffer, 0, prevLength);
                    data.Flush();

                    // Now we want to swap the two buffers, we don't care
                    // what happens to the data from prevBuffer so we set
                    // curBuffer to it so it gets overwrited.
                    byte[] tempBuffer = curBuffer;
                    curBuffer  = prevBuffer;
                    prevBuffer = tempBuffer;

                    // We don't need to swap the lengths because
                    // curLength will be overwritten in the next
                    // iteration of the loop.
                    prevLength = curLength;
                }while (prevLength != 0);

                data.Flush();
                data.Close();
                data.Dispose();
            }

            var contentType        = parameters.ContainsKey("content-type") ? parameters["content-type"] : "text/plain";
            var contentDisposition = parameters.ContainsKey("content-disposition") ? parameters["content-disposition"] : "form-data";

            var part = new HttpFile()
            {
                Name               = parameters["name"],
                FileName           = parameters["filename"],
                Extension          = parameters["filename"].Contains('.') ? parameters["filename"].Substring(parameters["filename"].LastIndexOf('.')) : "",
                TempFile           = temp,
                ContentType        = contentType,
                ContentDisposition = contentDisposition
            };

            return(part);
        }