/// <summary> /// Parses a section of the stream that is known to be parameter data. /// </summary> /// <param name="parameters"> /// The header parameters of this section. "name" must be a valid key. /// </param> /// <param name="reader"> /// The StreamReader to read the data from /// </param> /// <returns> /// The <see cref="ParameterPart" /> containing the parsed data (name, value). /// </returns> /// <exception cref="MultipartParseException"> /// thrown if unexpected data is found such as running out of stream before hitting the boundary. /// </exception> private void ParseParameterPart(Dictionary <string, string> parameters, RebufferableBinaryReader reader) { var data = new StringBuilder(); bool firstTime = true; string line = reader.ReadLine(); while (line != boundary && line != endBoundary) { if (line == null) { throw new MultipartParseException("Unexpected end of stream. Is there an end boundary?"); } if (firstTime) { data.Append(line); firstTime = false; } else { data.Append(Environment.NewLine); data.Append(line); } line = reader.ReadLine(); } if (line == endBoundary) { readEndBoundary = true; } var part = new ParameterPart(parameters["name"], data.ToString()); ParameterHandler(part); }
/// <summary> /// Detects the boundary from the input stream. Assumes that the /// current position of the reader is the start of the file and therefore /// the beginning of the boundary. /// </summary> /// <param name="reader"> /// The binary reader to parse /// </param> /// <returns> /// The boundary string /// </returns> private static string DetectBoundary(RebufferableBinaryReader reader) { string boundary = string.Concat(reader.ReadLine().Skip(2)); reader.Buffer("--" + boundary + "\n"); return(boundary); }
/// <summary> /// Parses the header of the next section of the multipart stream and /// determines if it contains file data or parameter data. /// </summary> /// <param name="reader"> /// The StreamReader to read data from. /// </param> /// <exception cref="MultipartParseException"> /// thrown if unexpected data is hit such as end of stream. /// </exception> private void ParseSection(RebufferableBinaryReader reader) { var parameters = new Dictionary <string, string>(); string line = reader.ReadLine(); while (line != string.Empty) { if (line == null) { throw new MultipartParseException("Unexpected end of stream"); } if (line == boundary || line == endBoundary) { throw new MultipartParseException("Unexpected end of section"); } Dictionary <string, string> values = SplitBySemicolonIgnoringSemicolonsInQuotes(line).Select(x => x.Split(new[] { ':', '=' }, 2)).Where(x => x.Length == 2).ToDictionary(x => x[0].Trim().Replace("\"", string.Empty).ToLower(), x => x[1].Trim().Replace("\"", string.Empty)); try { foreach (var pair in values) { parameters.Add(pair.Key, pair.Value); } } catch (ArgumentException) { throw new MultipartParseException("Duplicate field in section"); } line = reader.ReadLine(); } if (parameters.ContainsKey("filename")) { ParseFilePart(parameters, reader); } else { ParseParameterPart(parameters, reader); } }
/// <summary> /// Begins the parsing of the stream into objects. /// </summary> /// <param name="reader"> /// The multipart/form-data binary reader to parse from. /// </param> /// <exception cref="MultipartParseException"> /// thrown on finding unexpected data such as a boundary before we are ready for one. /// </exception> private void Parse(RebufferableBinaryReader reader) { while (true) { string line = reader.ReadLine(); if (line == boundary) { break; } if (line == null) { throw new MultipartParseException("Could not find expected boundary"); } } while (!readEndBoundary) { ParseSection(reader); } if (StreamClosedHandler != null) { StreamClosedHandler(); } }