//
// System.Net.HttpWebResponse
//
-// Author:
-// Lawrence Pit (loz@cable.a2000.nl)
+// Authors:
+// Lawrence Pit (loz@cable.a2000.nl)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// (c) 2002 Lawrence Pit
+// (c) 2003 Ximian, Inc. (http://www.ximian.com)
//
using System;
using System.IO;
+using System.Net.Sockets;
using System.Runtime.Serialization;
+using System.Text;
namespace System.Net
{
[Serializable]
public class HttpWebResponse : WebResponse, ISerializable, IDisposable
{
- private Uri uri;
- private WebHeaderCollection webHeaders;
- private CookieCollection cookieCollection = null;
- private string method = null;
- private Version version = null;
- private HttpStatusCode statusCode;
- private string statusDescription = null;
+ Uri uri;
+ WebHeaderCollection webHeaders;
+ CookieCollection cookieCollection;
+ string method;
+ Version version;
+ HttpStatusCode statusCode;
+ string statusDescription;
+ long contentLength = -1;
+ string contentType;
- private Stream responseStream;
- private bool disposed = false;
+ bool disposed = false;
+ WebConnectionStream stream;
// Constructors
- internal HttpWebResponse (Uri uri, string method, Stream responseStream)
- {
- Text.StringBuilder value = null;
- string last = null;
- string line = null;
- string[] protocol, header;
-
+ internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
+ {
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");
+ webHeaders = data.Headers;
+ version = data.Version;
+ statusCode = (HttpStatusCode) data.StatusCode;
+ statusDescription = data.StatusDescription;
+ stream = data.stream;
+ if (cookiesSet) {
+ FillCookies ();
+ } else if (webHeaders != null) {
+ webHeaders.RemoveInternal ("Set-Cookie");
+ webHeaders.RemoveInternal ("Set-Cookie2");
}
-
- this.statusCode = (HttpStatusCode) 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 (line.Trim());
- }
-
- this.webHeaders[last] = value.ToString(); // otherwise we miss the last header
}
-
+
protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
- throw new NotSupportedException ();
+ SerializationInfo info = serializationInfo;
+
+ uri = (Uri) info.GetValue ("uri", typeof (Uri));
+ contentLength = info.GetInt64 ("contentLength");
+ contentType = info.GetString ("contentType");
+ method = info.GetString ("method");
+ statusDescription = info.GetString ("statusDescription");
+ cookieCollection = (CookieCollection) info.GetValue ("cookieCollection", typeof (CookieCollection));
+ version = (Version) info.GetValue ("version", typeof (Version));
+ statusCode = (HttpStatusCode) info.GetValue ("statusCode", typeof (HttpStatusCode));
}
// Properties
// parameter = attribute "=" value
// 3.7.1. default is ISO-8859-1
get {
- try {
- string contentType = ContentType;
- if (contentType == null)
- return "ISO-8859-1";
- string val = contentType.ToLower ();
- int pos = val.IndexOf ("charset=");
- if (pos == -1)
- return "ISO-8859-1";
- pos += 8;
- int pos2 = val.IndexOf (';', pos);
- return (pos2 == -1)
- ? contentType.Substring (pos)
- : contentType.Substring (pos, pos2 - pos);
- } finally {
- CheckDisposed ();
- }
+ CheckDisposed ();
+ string contentType = ContentType;
+ if (contentType == null)
+ return "ISO-8859-1";
+ string val = contentType.ToLower ();
+ int pos = val.IndexOf ("charset=");
+ if (pos == -1)
+ return "ISO-8859-1";
+ pos += 8;
+ int pos2 = val.IndexOf (';', pos);
+ return (pos2 == -1)
+ ? contentType.Substring (pos)
+ : contentType.Substring (pos, pos2 - pos);
}
}
public string ContentEncoding {
get {
- try { return webHeaders ["Content-Encoding"]; }
- finally { CheckDisposed (); }
+ CheckDisposed ();
+ return webHeaders ["Content-Encoding"];
}
}
public override long ContentLength {
- get {
+ get {
+ CheckDisposed ();
+ if (contentLength != -1)
+ return contentLength;
+
try {
- return Int64.Parse (webHeaders ["Content-Length"]);
+ contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]);
} catch (Exception) {
return -1;
- } finally {
- CheckDisposed ();
}
+
+ return contentLength;
}
}
public override string ContentType {
- get {
- try { return webHeaders ["Content-Type"]; }
- finally { CheckDisposed (); }
+ get {
+ CheckDisposed ();
+ if (contentType == null)
+ contentType = webHeaders ["Content-Type"];
+
+ return contentType;
}
}
}
set {
CheckDisposed ();
- // ?? don't understand how you can set cookies on a response.
- throw new NotSupportedException ();
+ cookieCollection = value;
}
}
public string Server {
get {
- try {
- return webHeaders ["Server"];
- } finally {
- CheckDisposed ();
- }
+ CheckDisposed ();
+ return webHeaders ["Server"];
}
}
public override int GetHashCode ()
{
- try {
- return base.GetHashCode ();
- } finally {
- CheckDisposed ();
- }
+ CheckDisposed ();
+ return base.GetHashCode ();
}
public string GetResponseHeader (string headerName)
{
- try {
- return webHeaders [headerName];
- } finally {
- CheckDisposed ();
- }
+ CheckDisposed ();
+ string value = webHeaders [headerName];
+ return (value != null) ? value : "";
}
public override Stream GetResponseStream ()
{
- try {
- if (method.Equals ("HEAD")) // see par 4.3 & 9.4
- return Stream.Null;
- return responseStream;
- } finally {
- CheckDisposed ();
- }
+ CheckDisposed ();
+ if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
+ return Stream.Null;
+
+ return stream;
}
- [MonoTODO]
void ISerializable.GetObjectData (SerializationInfo serializationInfo,
StreamingContext streamingContext)
{
- CheckDisposed ();
- throw new NotImplementedException ();
+ SerializationInfo info = serializationInfo;
+
+ info.AddValue ("uri", uri);
+ info.AddValue ("contentLength", contentLength);
+ info.AddValue ("contentType", contentType);
+ info.AddValue ("method", method);
+ info.AddValue ("statusDescription", statusDescription);
+ info.AddValue ("cookieCollection", cookieCollection);
+ info.AddValue ("version", version);
+ info.AddValue ("statusCode", statusCode);
}
// Cleaning up stuff
- ~HttpWebResponse ()
- {
- Dispose (false);
- }
-
public override void Close ()
{
((IDisposable) this).Dispose ();
cookieCollection = null;
method = null;
version = null;
- // statusCode = null;
statusDescription = null;
}
// release unmanaged resources
- Stream stream = responseStream;
- responseStream = null;
- if (stream != null)
- stream.Close (); // also closes webRequest
+ Stream st = stream;
+ stream = null;
+ if (st != null)
+ st.Close ();
}
private void CheckDisposed ()
throw new ObjectDisposedException (GetType ().FullName);
}
- private static string ReadHttpLine (Stream stream)
+ void FillCookies ()
{
- 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;
- }
+ if (webHeaders == null)
+ return;
- line.Append (Convert.ToChar(buf[0]));
- if (read_last) {
- line.Append (Convert.ToChar (last));
- read_last = false;
- }
+ string val = webHeaders ["Set-Cookie"];
+ if (val != null && val.Trim () != "")
+ SetCookie (val);
+
+ val = webHeaders ["Set-Cookie2"];
+ if (val != null && val.Trim () != "")
+ SetCookie2 (val);
+ }
+
+ static string [] SplitValue (string input)
+ {
+ string [] result = new string [2];
+ int eq = input.IndexOf ('=');
+ if (eq == -1) {
+ result [0] = "invalid";
+ } else {
+ result [0] = input.Substring (0, eq).Trim ().ToUpper ();
+ result [1] = input.Substring (eq + 1);
}
- return line.ToString();
+ return result;
}
-
- private void SetCookie (string cookie_str)
+
+ [MonoTODO ("Parse dates")]
+ 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
+ parts = SplitValue ((string) options.Dequeue()); // 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
+ parts = SplitValue ((string) options.Dequeue());
+ switch (parts [0]) {
case "COMMENT":
if (cookie.Comment == null)
cookie.Comment = parts[1];
cookie.Discard = true;
break;
case "DOMAIN":
- if (cookie.Domain == null)
+ if (cookie.Domain == "")
cookie.Domain = parts[1];
break;
case "MAX-AGE": // RFC Style Set-Cookie2
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]);
+ if (cookie.Expires == DateTime.MinValue) {
+ //FIXME: Does DateTime parse something like: "Sun, 17-Jan-2038 19:14:07 GMT"?
+ //cookie.Expires = DateTime.ParseExact (parts[1]);
+ cookie.Expires = DateTime.Now.AddDays (1);
+ }
break;
case "PATH":
- if (cookie.Path == null)
cookie.Path = parts[1];
break;
case "PORT":
if (cookieCollection == null)
cookieCollection = new CookieCollection();
- if (cookie.Domain == null)
+ if (cookie.Domain == "")
cookie.Domain = uri.Host;
cookieCollection.Add (cookie);
}
- private void SetCookie2 (string cookies_str)
+ void SetCookie2 (string cookies_str)
{
- string[] cookies = cookies_str.Split (',');
+ string [] cookies = cookies_str.Split (',');
foreach (string cookie_str in cookies)
SetCookie (cookie_str);
-
}
}
}
+