This patch adds Cookie handling and more correct header handling
(doesn't assume that the next character after a \r is a \n being the
most important).
could someone please look over this and 1) tell me what I did wrong or
2) apply it?
Thanks
--Shahms
? .HttpWebResponse.cs.swp
Index: HttpWebRequest.cs
===================================================================
RCS file: /mono/mcs/class/System/System.Net/HttpWebRequest.cs,v
retrieving revision 1.5
diff -u -r1.5 HttpWebRequest.cs
--- HttpWebRequest.cs 28 May 2002 18:36:53 -0000 1.5
+++ HttpWebRequest.cs 3 Sep 2002 01:17:56 -0000
@@ -56,9 +56,9 @@
this.requestUri = uri;
this.actualUri = uri;
this.webHeaders = new WebHeaderCollection (true);
- // this.webHeaders.SetInternal ("Host", uri.Authority);
- // this.webHeaders.SetInternal ("Date",
DateTime.Now.ToUniversalTime ().ToString ("r", null));
- // this.webHeaders.SetInternal ("Expect", "100-continue");
+ this.webHeaders.SetInternal ("Host", uri.Authority);
+ this.webHeaders.SetInternal ("Date",
+DateTime.Now.ToUniversalTime ().ToString ("r", null));
+ this.webHeaders.SetInternal ("Expect", "100-continue");
this.method = "GET";
this.version = HttpVersion.Version11;
this.proxy = GlobalProxySelection.Select;
@@ -451,7 +451,7 @@
internal Stream GetRequestStreamInternal ()
{
- this.requestStream = null; // TODO: new HttpWebStream (this);
+ this.requestStream = new HttpWebStream (this);
return this.requestStream;
}
@@ -512,7 +512,7 @@
if (requestEndEvent != null) {
requestEndEvent.WaitOne ();
}
- Stream responseStream = null; // TODO: new HttpWebStream
(this);
+ Stream responseStream = new HttpWebStream (this);
this.webResponse = new HttpWebResponse (this.actualUri,
method, responseStream);
return (WebResponse) this.webResponse;
}
@@ -557,16 +557,41 @@
// Private Classes
// to catch the Close called on the NetworkStream
- /*
- internal class HttpWebStream : Stream
+ internal class HttpWebStream : NetworkStream
{
HttpWebRequest webRequest;
- internal HttpWebStream (HttpWebRequest webRequest)
- : base (webRequest.RequestUri)
+ internal HttpWebStream (HttpWebRequest webRequest)
+ : base (HttpWebStream.CreateSocket (webRequest), true)
{
+ StreamWriter webWriter = null;
+ string headerValue = null;
+
+
+ webWriter = new StreamWriter (this);
+
+ webWriter.Write (webRequest.Method + " " +
+webRequest.actualUri.AbsolutePath + " HTTP/1.1\r\n");
+
+ foreach (string header in webRequest.webHeaders) {
+ headerValue = header + ": " +
+webRequest.webHeaders[header] + "\r\n";
+ webWriter.Write (headerValue);
+ }
+ webWriter.Write ("\r\n");
+ webWriter.Flush();
+
this.webRequest = webRequest;
}
+
+ private static Socket CreateSocket (HttpWebRequest webRequest)
+ {
+ IPAddress hostAddr = Dns.Resolve
+(webRequest.actualUri.Host).AddressList[0];
+ IPEndPoint endPoint = new IPEndPoint (hostAddr,
+webRequest.actualUri.Port);
+ Socket socket = new Socket(AddressFamily.InterNetwork,
+SocketType.Stream,
+ ProtocolType.Tcp);
+
+ socket.Connect (endPoint);
+ return socket;
+ }
public override void Close()
{
@@ -574,6 +599,5 @@
webRequest.Close ();
}
}
- */
}
-}
\ No newline at end of file
+}
Index: HttpWebResponse.cs
===================================================================
RCS file: /mono/mcs/class/System/System.Net/HttpWebResponse.cs,v
retrieving revision 1.4
diff -u -r1.4 HttpWebResponse.cs
--- HttpWebResponse.cs 28 May 2002 18:36:53 -0000 1.4
+++ HttpWebResponse.cs 3 Sep 2002 01:17:56 -0000
@@ -29,13 +29,54 @@
internal HttpWebResponse (Uri uri, string method, Stream
responseStream)
{
+ Text.StringBuilder value = null;
+ string last = null;
+ string line = null;
+ string[] protocol, header;
+
this.uri = uri;
this.method = method;
this.responseStream = responseStream;
+ this.webHeaders = new WebHeaderCollection();
+
+ line = ReadHttpLine(responseStream);
+ protocol = line.Split (' ');
+
+ switch (protocol[0]) {
+ case "HTTP/1.0":
+ this.version = HttpVersion.Version10;
+ break;
+ case "HTTP/1.1":
+ this.version = HttpVersion.Version11;
+ break;
+ default:
+ throw new WebException ("Unrecognized HTTP
+Version");
+ }
- // TODO: parse headers from responseStream
+ this.statusCode = Int32.Parse (protocol[1]);
+
+ while ((line = ReadHttpLine(responseStream)).Length != 0) {
+ if (!Char.IsWhiteSpace (line[0])) { // new header
+ header = line.Split (new char[] {':'}, 2);
+ if (header.Length != 2)
+ throw new WebException ("Bad HTTP
+Header");
+ if (last != null) { // not the first header
+ if (last.Equals ("Set-Cookie"))
+ SetCookie (value.ToString());
+ else if (last.Equals ("Set-Cookie2"))
+ SetCookie2 (value.ToString());
+ else //don't save Set-Cookie headers
+ this.webHeaders[last] =
+value.ToString();
+ }
+ last = header[0];
+ value = new Text.StringBuilder
+(header[1].Trim());
+ }
+ else
+ value.Append (header[0].Trim());
+ }
- this.statusCode = HttpStatusCode.OK;
+ this.webHeaders[last] = value.ToString(); // otherwise we miss
+the last header
+ // TODO: parse cookies from headers
}
protected HttpWebResponse (SerializationInfo serializationInfo,
StreamingContext streamingContext)
@@ -100,11 +141,6 @@
get {
CheckDisposed ();
- // LAMESPEC: a simple test reveal this always
- // returns an empty collection. It is not filled
- // with the values from the Set-Cookie or
- // Set-Cookie2 response headers, which is a bit
- // of a shame..
if (cookieCollection == null)
cookieCollection = new CookieCollection ();
return cookieCollection;
@@ -267,5 +303,98 @@
if (disposed)
throw new ObjectDisposedException (GetType
().FullName);
}
+
+ private static string ReadHttpLine (Stream stream)
+ {
+ Text.StringBuilder line = new Text.StringBuilder();
+ byte last = (byte)'\n';
+ bool read_last = false;
+ byte[] buf = new byte[1]; // one at a time to not snarf too
+much
+
+ while (stream.Read (buf, 0, buf.Length) != 0) {
+ if (buf[0] == '\r') {
+ if ((last = (byte)stream.ReadByte ()) == '\n')
+// headers; not at EOS
+ break;
+ read_last = true;
+ }
+
+ line.Append (Convert.ToChar(buf[0]));
+ if (read_last) {
+ line.Append (Convert.ToChar (last));
+ read_last = false;
+ }
+ }
+
+ return line.ToString();
+ }
+
+ private void SetCookie (string cookie_str)
+ {
+ string[] parts = null;
+ Collections.Queue options = null;
+ Cookie cookie = null;
+
+ options = new Collections.Queue (cookie_str.Split (';'));
+ parts = ((string)options.Dequeue()).Split ('='); // NAME=VALUE
+must be first
+
+ cookie = new Cookie (parts[0], parts[1]);
+
+ while (options.Count > 0) {
+ parts = ((string)options.Dequeue()).Split ('=');
+ switch (parts[0].ToUpper()) { // cookie options are
+case-insensitive
+ case "COMMENT":
+ if (cookie.Comment == String.Empty)
+ cookie.Comment = parts[1];
+ break;
+ case "COMMENTURL":
+ if (cookie.CommentUri == null)
+ cookie.CommentUri = new
+Uri(parts[1]);
+ break;
+ case "DISCARD":
+ cookie.Discard = true;
+ break;
+ case "DOMAIN":
+ if (cookie.Domain == String.Empty)
+ cookie.Domain = parts[1];
+ break;
+ case "MAX-AGE": // RFC Style Set-Cookie2
+ if (cookie.Expires ==
+DateTime.MinValue)
+ cookie.Expires =
+cookie.TimeStamp.AddSeconds (Int32.Parse (parts[1]));
+ break;
+ case "EXPIRES": // Netscape Style Set-Cookie
+ if (cookie.Expires ==
+DateTime.MinValue)
+ cookie.Expires =
+DateTime.Parse (parts[1]);
+ break;
+ case "PATH":
+ if (cookie.Path == String.Empty)
+ cookie.Path = parts[1];
+ break;
+ case "PORT":
+ if (cookie.Port == String.Empty)
+ cookie.Port = parts[1];
+ break;
+ case "SECURE":
+ cookie.Secure = true;
+ break;
+ case "VERSION":
+ cookie.Version = Int32.Parse
+(parts[1]);
+ break;
+ } // switch
+ } // while
+
+ if (cookieCollection == null)
+ cookieCollection = new CookieCollection();
+
+ cookieCollection.Add (cookie);
+ }
+
+ private void SetCookie2 (string cookies_str)
+ {
+ string[] cookies = cookies_str.Split (',');
+
+ foreach (string cookie_str in cookies)
+ SetCookie (cookie_str);
+
+ }
}
-}
\ No newline at end of file
+}