[Mono-bugs] [Bug 43362][Maj] New - multipart form data bug

bugzilla-daemon@rocky.ximian.com bugzilla-daemon@rocky.ximian.com
Tue, 20 May 2003 05:58:35 -0400 (EDT)


Please do not reply to this email- if you want to comment on the bug, go to the
URL shown below and enter your comments there.

Changed by mark_kuschnir@yahoo.co.uk.

http://bugzilla.ximian.com/show_bug.cgi?id=43362

--- shadow/43362	Tue May 20 05:58:35 2003
+++ shadow/43362.tmp.16306	Tue May 20 05:58:35 2003
@@ -0,0 +1,340 @@
+Bug#: 43362
+Product: Mono/Class Libraries
+Version: unspecified
+OS: 
+OS Details: Windows 2000 with all service packs
+Status: NEW   
+Resolution: 
+Severity: 
+Priority: Major
+Component: System.Web
+AssignedTo: mono-bugs@ximian.com                            
+ReportedBy: Mark_Kuschnir@yahoo.co.uk               
+QAContact: mono-bugs@ximian.com
+TargetMilestone: ---
+URL: 
+Cc: 
+Summary: multipart form data bug
+
+Please fill in this template when reporting a bug, unless you know what 
+you are doing.
+
+Description of Problem:
+The following complete program (InsertTest.cs) demonstrates the problem 
+with Mono 0.24. Basically I'm building up a multipart form and sending it 
+to a database (Tamino). The only trouble is that with Mono the data sent 
+is incomplete. I was using HttpSniffer.pl (www.schmerg.com) on port 8000 
+to demonstrate this. I'm sure you don't need a database to be able to see 
+that the sent data is incomplete. I suspect that it only happens with 
+messages of a particular size hence the nonsense document contained in the 
+program.
+
+Steps:
+1. mcs -target:exe InsertTest.cs
+2. mono InsertTest.exe
+
+Actual Results:
+Incomplete message transmitted.
+
+Expected Results:
+In .NET the message is sent correctly.
+
+How often does this happen? 
+Always.
+
+
+
+Additional Information:
+
+using System;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Xml;
+using System.Collections.Specialized;
+
+/// <summary>
+/// Base HTTP request.
+/// </summary>
+
+internal class HttpRequest
+{
+	/// <summary>
+	/// HTTP request.
+	/// </summary>
+	protected HttpWebRequest m_req;
+
+	//=================================================================
+===
+	/// <summary>
+	/// Construct a request object tied to the specified url.
+	/// </summary>
+	///	<param name="url">url the request is for</param>
+	///	<param name="method">request method</param>
+		
+	internal HttpRequest(string url, string method)
+	{
+		m_req = (HttpWebRequest) WebRequest.Create(url);
+		m_req.Method = method;
+		m_req.Headers["Accept-Charset"] = "utf-8";
+		m_req.UserAgent = "InsertTest";
+	}
+		
+	//=================================================================
+===
+	/// <summary>
+	/// Allow the HTTP header "Content-Type" to be specified.
+	/// </summary>
+
+	internal string ContentType
+	{
+		set { m_req.ContentType = value; }
+	}
+
+	//=================================================================
+===
+	/// <summary>
+	/// Set header to specified value.
+	/// </summary>
+	/// <param name="name">header name</param>
+	/// <param name="val">header value</param>
+
+	internal void SetHeader(string name, string val)
+	{
+		m_req.Headers[name] = val;
+	}
+
+	//=================================================================
+===
+	/// <summary>
+	/// Add the specified stream data to the request stream.
+	/// Attempt to reset the user's request stream (requires CanSeek).
+	/// </summary>
+	/// <param name="dataStream">stream to write</param>
+	/// <remarks>This is a single shot method!
+	/// Once used the request stream will be closed.</remarks>
+
+	internal void Write(Stream dataStream)
+	{
+		Stream reqStream = m_req.GetRequestStream();
+
+		// attempt to reset the stream for the user
+		if (dataStream.CanSeek) dataStream.Position = 0;
+
+		byte[] data = new byte[8192];
+		int len;
+
+		while ((len = dataStream.Read(data, 0, data.GetLength
+(0))) != 0)
+		{
+			reqStream.Write(data, 0, len);
+		}
+
+		reqStream.Flush();
+		reqStream.Close();
+	}
+
+	//=================================================================
+===
+	/// <summary>
+	/// Get response.
+	/// </summary>
+		
+	internal void Response()
+	{
+		HttpWebResponse res = (HttpWebResponse) m_req.GetResponse
+();
+		// res.Headers
+		// res.GetResponseStream()
+		Console.WriteLine("StatusCode: "+res.StatusCode.ToString
+());
+	}
+}
+
+/// <summary>
+/// Implement an HTTP POST request.
+/// </summary>
+
+internal class HttpPostRequest : HttpRequest
+{
+	/// <summary>
+	/// The boundary constant for the multipart/form-data HTTP 
+requests.
+	/// </summary>
+	const string BOUNDARY = "---------------------------7d16151062e";
+	
+	/// <summary>
+	/// The start boundary constant for the multipart/form-data HTTP 
+requests.
+	/// </summary>
+	const string START_BOUNDARY = "--" + BOUNDARY;
+	
+	/// <summary>
+	/// The end boundary constant for the multipart/form-data HTTP 
+requests.
+	/// </summary>
+	const string END_BOUNDARY = START_BOUNDARY + "--";
+	
+	/// <summary>
+	/// The line separator constant, which is for multipart/form-data 
+CRLF.
+	/// </summary>
+	const string LINE_SEPARATOR = "\r\n";
+
+	/// <summary>
+	/// Request output stream.
+	/// </summary>
+	StreamWriter m_writer;
+        		
+	//=================================================================
+===
+	/// <summary>
+	/// Construct a request object tied to the specified url.
+	/// </summary>
+	///	<param name="url">url the request is for</param>
+		
+	internal HttpPostRequest(string url) : base(url, "POST")
+	{
+		m_req.ContentType = "multipart/form-data; boundary=" + 
+BOUNDARY;
+
+		m_writer = new StreamWriter(m_req.GetRequestStream());
+	}
+					
+	//=================================================================
+===
+	/// <summary>
+	/// Beginning of message.
+	/// </summary>
+		
+	internal void BeginMessage()
+	{
+	}
+
+	//=================================================================
+===
+	/// <summary>
+	/// Write the specified name/value pair.
+	/// </summary>
+	/// <param name="name">data name</param>
+	/// <param name="val">data value</param>
+		
+	internal void Write(string name, string val)
+	{
+		m_writer.Write(START_BOUNDARY);
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write("Content-disposition: form-data; 
+name=\""+name+"\"");
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write(val);
+		m_writer.Write(LINE_SEPARATOR);
+	}
+		
+	//=================================================================
+===
+	/// <summary>
+	/// Write the specified command/XML pair.
+	/// </summary>
+	/// <param name="cmd">X machine command to be performed</param>
+	/// <param name="node">XML that the command is for</param>
+		
+	internal void Write(string cmd, XmlNode node)
+	{
+		m_writer.Write(START_BOUNDARY);
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write("Content-disposition: form-data; 
+name=\""+cmd+"\"");
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write("Content-Type: "+"text/xml");
+		m_writer.Write(LINE_SEPARATOR);
+		m_writer.Write(LINE_SEPARATOR);
+		XmlTextWriter xtw = new XmlTextWriter(m_writer);
+		node.WriteTo(xtw);
+		m_writer.Write(LINE_SEPARATOR);
+	}
+		
+	//=================================================================
+===
+	/// <summary>
+	/// End of message.
+	/// </summary>
+		
+	internal void EndMessage()
+	{
+		m_writer.Write(END_BOUNDARY);
+		m_writer.Flush();
+
+		m_writer.Close();
+	}
+}
+
+public class InsertDocuments
+{
+	/// <summary>
+	/// The main entry point for the application.
+	/// </summary>
+	[STAThread]
+	static void Main(string[] args)
+	{
+		// load the XML data
+		XmlDocument data = new XmlDocument();
+		data.LoadXml(XML);
+
+		HttpPostRequest req = new HttpPostRequest
+("http://localhost:8000/tamino/mydb/ino:etc");
+		req.BeginMessage();
+		req.Write("_encoding", "utf-8");
+		req.Write("_process", data.DocumentElement);
+		req.EndMessage();
+	}
+
+	const string XML =
+@"<DataBlob>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+<Item>
+123456789012345678901234567890123456789012345678901234567890123456789012345
+67890
+</Item>
+</DataBlob>
+";
+}