public static Task <FormData> ParseMultipart(Stream stream, string boundary) { if (stream == null) { throw new ArgumentNullException("stream"); } if (boundary == null) { throw new ArgumentNullException("boundary"); } if (boundary.Length == 0) { throw new ArgumentException("Boundary cannot be empty", "boundary"); } var form = new FormData(); boundary = "--" + boundary; var boundaryBytes = Encoding.UTF8.GetBytes("\r\n" + boundary); string currentLine = stream.ReadLine(Encoding.UTF8); if (currentLine != boundary) { form.IsValid = false; return(OwinConstants.TaskHelper.Completed(form)); } while (true) { currentLine = stream.ReadLine(Encoding.UTF8); // parse ContentDisposition line var match = ContentDispositionFormDataRegex.Match(currentLine); if (!match.Success) { form.IsValid = false; return(OwinConstants.TaskHelper.Completed(form)); } string fieldName = match.Groups[1].Value; string fileName = match.Groups[2].Success ? match.Groups[3].Value : null; if (fileName != null) { if (!ParseMultipartFile(stream, form, fieldName, fileName, boundaryBytes)) { form.IsValid = false; return(OwinConstants.TaskHelper.Completed(form)); } } else { if (!ParseMultipartField(stream, form, fieldName, boundaryBytes)) { form.IsValid = false; return(OwinConstants.TaskHelper.Completed(form)); } } // check end or next currentLine = stream.ReadLine(Encoding.UTF8); // --boundary-- end if (currentLine == "--") { break; } // --boundary between if (currentLine != string.Empty) { form.IsValid = false; return(OwinConstants.TaskHelper.Completed(form)); } } return(OwinConstants.TaskHelper.Completed(form)); }
private static bool ParseMultipartField(Stream stream, FormData form, string fieldName, byte[] boundaryBytes) { string contentType = null; string headerLine; Match match; while ((headerLine = stream.ReadLine(Encoding.UTF8)) != string.Empty) { // parse 'Content-" headers match = ContentTypeFormDataRegex.Match(headerLine); if (match.Success) { // nested: Content-Type: multipart/mixed; boundary=BbC04y contentType = match.Groups[1].Value.Trim(); if (match.Groups[2].Success) { string fileBoundary = match.Groups[4].Value; byte[] fileBoundaryBytes = Encoding.UTF8.GetBytes("\r\n--" + fileBoundary); byte[] temp; if (!stream.ReadTo(fileBoundaryBytes, out temp)) { return(false); } if (stream.ReadLine(Encoding.UTF8) != string.Empty) { return(false); } bool moreFiles = true; while (moreFiles) { string line = stream.ReadLine(Encoding.UTF8); match = ContentDispositionFileRegex.Match(line); if (!match.Success) { return(false); } string filename = match.Groups[1].Value; if (!ParseMultipartFile(stream, form, fieldName, filename, fileBoundaryBytes)) { return(false); } line = stream.ReadLine(Encoding.UTF8); if (line == "--") { moreFiles = false; } else if (line != string.Empty) { return(false); } } // NB: CrLf already ripped here var boundaryNoCrLf = new byte[boundaryBytes.Length - 2]; Array.Copy(boundaryBytes, 2, boundaryNoCrLf, 0, boundaryBytes.Length - 2); if (!stream.ReadTo(boundaryNoCrLf, out temp)) { return(false); } if (temp.Length != 0) { return(false); } return(true); } } } if (contentType == null) { contentType = "text/plain"; } byte[] value; if (!stream.ReadTo(boundaryBytes, out value)) { return(false); } // handle charset: content-type: text/plain;charset=windows-1250 match = CharsetRegex.Match(contentType); Encoding encoding = match.Success ? Encoding.GetEncoding(match.Groups[2].Value) : Encoding.UTF8; form[fieldName] = encoding.GetString(value); return(true); }