// // System.Web.HttpMultipartContentParser // // Authors: // Ben Maurer (bmaurer@users.sourceforge.net) // // (c) 2003 Ben Maurer // using System; using System.Collections; using System.Collections.Specialized; using System.IO; using System.Text; using System.Web.Configuration; using System.Web.Util; namespace System.Web { internal class HttpMultipartContentParser { const byte HYPHEN = (byte) '-', LF = (byte) '\n', CR = (byte) '\r'; public static MultipartContentElement [] Parse (byte [] data, byte [] boundary, Encoding encoding) { HttpMultipartContentParser p = new HttpMultipartContentParser (data, boundary, encoding); p.ParseIntoElementList(); return (MultipartContentElement []) p.elements.ToArray (typeof (MultipartContentElement)); } HttpMultipartContentParser (byte [] data, byte [] boundary, Encoding encoding) { this.data = data; this.boundary = boundary; this.enc = encoding; this.len = data.Length; } bool IsAtBoundaryLine () { int boundaryLen = boundary.Length; if (lineLen != boundaryLen && lineLen != boundaryLen + 2) return false; for (int i = 0; i < boundaryLen; i++) if (data [lineStart + i] != boundary [i]) return false; if (lineLen == boundaryLen) return true; if (data [lineStart + boundaryLen ] != HYPHEN || data [lineStart + boundaryLen + 1] != HYPHEN) return false; lastBoundaryFound = true; return true; } string GetAttributeFromContentDispositionHeader (string l, int pos, string name) { string nameEqQuote = name + "=\""; int idxVal = l.IndexOf (nameEqQuote, pos); if (idxVal < 0) return null; idxVal += nameEqQuote.Length; int idxEndQuote = l.IndexOf ('"', idxVal); if (idxEndQuote < 0) return null; if (idxEndQuote == idxVal) return ""; return l.Substring (idxVal, idxEndQuote - idxVal); } bool IsAtEndOfData () { return pos >= len || lastBoundaryFound; } private bool GetNextLine() { int pos = this.pos; lineStart = -1; while (pos < len && !(this.data [pos] == LF || ++pos + 1 == len)) ; if (pos >= len) return false; lineStart = this.pos; lineLen = pos - lineStart; this.pos = pos + 1; if (lineLen > 0 && data [pos - 1] == CR) lineLen--; return true; } void ParseIntoElementList () { while (!IsAtBoundaryLine () && GetNextLine ()) ; do { partName = partFilename = partContentType = null; while (this.GetNextLine () && lineLen != 0) { string line = enc.GetString (data, lineStart, lineLen); int colonPos = line.IndexOf(':'); if (colonPos < 0) continue; string headerName = line.Substring (0, colonPos); if (String.Compare (headerName, "Content-Disposition", true) == 0) { partName = GetAttributeFromContentDispositionHeader (line, colonPos + 1, "name"); partFilename = GetAttributeFromContentDispositionHeader (line, colonPos + 1, "filename"); } else if (String.Compare (headerName, "Content-Type", true) == 0) partContentType = line.Substring (colonPos + 1).Trim (); } if (IsAtEndOfData ()) break; partDataStart = pos; partDataLength = -1; while (GetNextLine ()) { if (!IsAtBoundaryLine ()) continue; int end = lineStart - 1; if (data [end] == LF) end--; if (data [end] == CR) end--; partDataLength = end - partDataStart + 1; break; } if (partDataLength == -1) break; if (partName != null) { elements.Add (new MultipartContentElement ( partName, partFilename, partContentType, data, partDataStart, partDataLength )); } } while (!IsAtEndOfData ()); } byte [] data, boundary; ArrayList elements = new ArrayList (); Encoding enc; bool lastBoundaryFound; int len, lineLen, lineStart; int partDataStart, partDataLength; string partContentType, partName, partFilename; int pos; } internal class MultipartContentElement { string name, fileName, contentType; byte [] data; int offset, len; public MultipartContentElement (string name, string fileName, string contentType, byte [] data, int offset, int len) { this.name = name; this.fileName = fileName; this.contentType = contentType; this.data = data; this.offset = offset; this.len = len; } public bool IsFile { get { return fileName != null; } } public bool IsFormItem { get { return fileName == null; } } public string Name { get { return name; } } public string GetString (Encoding enc) { if (len == 0) return ""; return enc.GetString (data, offset, len); } public HttpPostedFile GetFile () { return new HttpPostedFile (fileName, contentType, new HttpRequestStream (data, offset, len)); } } }