-//\r
-// System.Net.HttpWebResponse\r
-//\r
-// Author:\r
-// Lawrence Pit (loz@cable.a2000.nl)\r
-//\r
-\r
-using System;\r
-using System.IO;\r
-using System.Runtime.Serialization;\r
-\r
-namespace System.Net \r
-{\r
- [Serializable]\r
- public class HttpWebResponse : WebResponse, ISerializable, IDisposable\r
- {\r
- private Uri uri;\r
- private WebHeaderCollection webHeaders;\r
- private CookieCollection cookieCollection = null;\r
- private string method = null;\r
- private Version version = null;\r
- private HttpStatusCode statusCode;\r
- private string statusDescription = null;\r
-\r
- private Stream responseStream; \r
- private bool disposed = false;\r
- \r
- // Constructors\r
- \r
- internal HttpWebResponse (Uri uri, string method, Stream responseStream) \r
- { \r
- this.uri = uri;\r
- this.method = method;\r
- this.responseStream = responseStream;\r
- \r
- // TODO: parse headers from responseStream\r
- \r
- this.statusCode = HttpStatusCode.OK;\r
- }\r
- \r
- protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)\r
- {\r
- throw new NotSupportedException ();\r
- }\r
- \r
- // Properties\r
- \r
- public string CharacterSet {\r
- // Content-Type = "Content-Type" ":" media-type\r
- // media-type = type "/" subtype *( ";" parameter )\r
- // parameter = attribute "=" value\r
- // 3.7.1. default is ISO-8859-1\r
- get { \r
- try {\r
- string contentType = ContentType;\r
- if (contentType == null)\r
- return "ISO-8859-1";\r
- string val = contentType.ToLower (); \r
- int pos = val.IndexOf ("charset=");\r
- if (pos == -1)\r
- return "ISO-8859-1";\r
- pos += 8;\r
- int pos2 = val.IndexOf (';', pos);\r
- return (pos2 == -1)\r
- ? contentType.Substring (pos) \r
- : contentType.Substring (pos, pos2 - pos);\r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- }\r
- \r
- public string ContentEncoding {\r
- get { \r
- try { return webHeaders ["Content-Encoding"]; }\r
- finally { CheckDisposed (); }\r
- }\r
- }\r
- \r
- public override long ContentLength { \r
- get { \r
- try {\r
- return Int64.Parse (webHeaders ["Content-Length"]); \r
- } catch (Exception) {\r
- return -1;\r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- }\r
- \r
- public override string ContentType { \r
- get { \r
- try { return webHeaders ["Content-Type"]; }\r
- finally { CheckDisposed (); }\r
- }\r
- }\r
- \r
- public CookieCollection Cookies {\r
- get { \r
- CheckDisposed ();\r
- \r
- // LAMESPEC: a simple test reveal this always \r
- // returns an empty collection. It is not filled \r
- // with the values from the Set-Cookie or \r
- // Set-Cookie2 response headers, which is a bit\r
- // of a shame..\r
- if (cookieCollection == null)\r
- cookieCollection = new CookieCollection ();\r
- return cookieCollection;\r
- }\r
- set {\r
- CheckDisposed ();\r
- // ?? don't understand how you can set cookies on a response.\r
- throw new NotSupportedException ();\r
- }\r
- }\r
- \r
- public override WebHeaderCollection Headers { \r
- get { \r
- CheckDisposed ();\r
- return webHeaders; \r
- }\r
- }\r
- \r
- public DateTime LastModified {\r
- get {\r
- CheckDisposed ();\r
- try {\r
- string dtStr = webHeaders ["Last-Modified"];\r
- // TODO: accept more than rfc1123 dates\r
- DateTime dt = DateTime.ParseExact (dtStr, "r", null);\r
- return dt;\r
- } catch (Exception) {\r
- return DateTime.Now; \r
- }\r
- }\r
- }\r
- \r
- public string Method {\r
- get { \r
- CheckDisposed ();\r
- return method; \r
- }\r
- }\r
- \r
- public Version ProtocolVersion {\r
- get { \r
- CheckDisposed ();\r
- return version; \r
- }\r
- }\r
- \r
- public override Uri ResponseUri { \r
- get { \r
- CheckDisposed ();\r
- return uri; \r
- }\r
- } \r
- \r
- public string Server {\r
- get { \r
- try {\r
- return webHeaders ["Server"]; \r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- }\r
- \r
- public HttpStatusCode StatusCode {\r
- get { \r
- CheckDisposed ();\r
- return statusCode; \r
- }\r
- }\r
- \r
- public string StatusDescription {\r
- get { \r
- CheckDisposed ();\r
- return statusDescription; \r
- }\r
- }\r
-\r
- // Methods\r
- \r
- public override int GetHashCode ()\r
- {\r
- try {\r
- return base.GetHashCode ();\r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- \r
- public string GetResponseHeader (string headerName)\r
- {\r
- try {\r
- return webHeaders [headerName];\r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- \r
- public override Stream GetResponseStream ()\r
- {\r
- try {\r
- if (method.Equals ("HEAD")) // see par 4.3 & 9.4\r
- return Stream.Null; \r
- return responseStream;\r
- } finally {\r
- CheckDisposed ();\r
- }\r
- }\r
- \r
- [MonoTODO]\r
- void ISerializable.GetObjectData (SerializationInfo serializationInfo,\r
- StreamingContext streamingContext)\r
- {\r
- CheckDisposed ();\r
- throw new NotImplementedException ();\r
- } \r
-\r
-\r
- // Cleaning up stuff\r
-\r
- ~HttpWebResponse ()\r
- {\r
- Dispose (false);\r
- } \r
- \r
- public override void Close ()\r
- {\r
- ((IDisposable) this).Dispose ();\r
- }\r
- \r
- void IDisposable.Dispose ()\r
- {\r
- Dispose (true);\r
- GC.SuppressFinalize (this); \r
- }\r
- \r
- protected virtual void Dispose (bool disposing) \r
- {\r
- if (this.disposed)\r
- return;\r
- this.disposed = true;\r
- \r
- if (disposing) {\r
- // release managed resources\r
- uri = null;\r
- webHeaders = null;\r
- cookieCollection = null;\r
- method = null;\r
- version = null;\r
- // statusCode = null;\r
- statusDescription = null;\r
- }\r
- \r
- // release unmanaged resources\r
- Stream stream = responseStream;\r
- responseStream = null;\r
- if (stream != null)\r
- stream.Close (); // also closes webRequest \r
- }\r
- \r
- private void CheckDisposed () \r
- {\r
- if (disposed)\r
- throw new ObjectDisposedException (GetType ().FullName);\r
- }\r
- } \r
-}
\ No newline at end of file
+//
+// System.Net.HttpWebResponse
+//
+// 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
+ {
+ Uri uri;
+ WebHeaderCollection webHeaders;
+ CookieCollection cookieCollection;
+ string method;
+ Version version;
+ HttpStatusCode statusCode;
+ string statusDescription;
+ long contentLength = -1;
+ string contentType;
+
+ bool disposed = false;
+ WebConnectionStream stream;
+
+ // Constructors
+
+ internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
+ {
+ this.uri = uri;
+ this.method = method;
+ 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");
+ }
+ }
+
+ protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
+ {
+ 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
+
+ public string CharacterSet {
+ // Content-Type = "Content-Type" ":" media-type
+ // media-type = type "/" subtype *( ";" parameter )
+ // parameter = attribute "=" value
+ // 3.7.1. default is ISO-8859-1
+ get {
+ 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 {
+ CheckDisposed ();
+ return webHeaders ["Content-Encoding"];
+ }
+ }
+
+ public override long ContentLength {
+ get {
+ CheckDisposed ();
+ if (contentLength != -1)
+ return contentLength;
+
+ try {
+ contentLength = (long) UInt64.Parse (webHeaders ["Content-Length"]);
+ } catch (Exception) {
+ return -1;
+ }
+
+ return contentLength;
+ }
+ }
+
+ public override string ContentType {
+ get {
+ CheckDisposed ();
+ if (contentType == null)
+ contentType = webHeaders ["Content-Type"];
+
+ return contentType;
+ }
+ }
+
+ public CookieCollection Cookies {
+ get {
+ CheckDisposed ();
+
+ if (cookieCollection == null)
+ cookieCollection = new CookieCollection ();
+ return cookieCollection;
+ }
+ set {
+ CheckDisposed ();
+ cookieCollection = value;
+ }
+ }
+
+ public override WebHeaderCollection Headers {
+ get {
+ CheckDisposed ();
+ return webHeaders;
+ }
+ }
+
+ public DateTime LastModified {
+ get {
+ CheckDisposed ();
+ try {
+ string dtStr = webHeaders ["Last-Modified"];
+ return MonoHttpDate.Parse (dtStr);
+ } catch (Exception) {
+ return DateTime.Now;
+ }
+ }
+ }
+
+ public string Method {
+ get {
+ CheckDisposed ();
+ return method;
+ }
+ }
+
+ public Version ProtocolVersion {
+ get {
+ CheckDisposed ();
+ return version;
+ }
+ }
+
+ public override Uri ResponseUri {
+ get {
+ CheckDisposed ();
+ return uri;
+ }
+ }
+
+ public string Server {
+ get {
+ CheckDisposed ();
+ return webHeaders ["Server"];
+ }
+ }
+
+ public HttpStatusCode StatusCode {
+ get {
+ CheckDisposed ();
+ return statusCode;
+ }
+ }
+
+ public string StatusDescription {
+ get {
+ CheckDisposed ();
+ return statusDescription;
+ }
+ }
+
+ // Methods
+
+ public override int GetHashCode ()
+ {
+ CheckDisposed ();
+ return base.GetHashCode ();
+ }
+
+ public string GetResponseHeader (string headerName)
+ {
+ CheckDisposed ();
+ string value = webHeaders [headerName];
+ return (value != null) ? value : "";
+ }
+
+ public override Stream GetResponseStream ()
+ {
+ CheckDisposed ();
+ if (0 == String.Compare (method, "HEAD", true)) // see par 4.3 & 9.4
+ return Stream.Null;
+
+ return stream;
+ }
+
+ void ISerializable.GetObjectData (SerializationInfo serializationInfo,
+ StreamingContext streamingContext)
+ {
+ 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
+
+ public override void Close ()
+ {
+ ((IDisposable) this).Dispose ();
+ }
+
+ void IDisposable.Dispose ()
+ {
+ Dispose (true);
+ GC.SuppressFinalize (this);
+ }
+
+ protected virtual void Dispose (bool disposing)
+ {
+ if (this.disposed)
+ return;
+ this.disposed = true;
+
+ if (disposing) {
+ // release managed resources
+ uri = null;
+ webHeaders = null;
+ cookieCollection = null;
+ method = null;
+ version = null;
+ statusDescription = null;
+ }
+
+ // release unmanaged resources
+ Stream st = stream;
+ stream = null;
+ if (st != null)
+ st.Close ();
+ }
+
+ private void CheckDisposed ()
+ {
+ if (disposed)
+ throw new ObjectDisposedException (GetType ().FullName);
+ }
+
+ void FillCookies ()
+ {
+ if (webHeaders == null)
+ return;
+
+ 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 result;
+ }
+
+ [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 = SplitValue ((string) options.Dequeue()); // NAME=VALUE must be first
+
+ cookie = new Cookie (parts[0], parts[1]);
+
+ while (options.Count > 0) {
+ parts = SplitValue ((string) options.Dequeue());
+ switch (parts [0]) {
+ case "COMMENT":
+ if (cookie.Comment == null)
+ 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 == "")
+ 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) {
+ //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":
+ cookie.Path = parts[1];
+ break;
+ case "PORT":
+ if (cookie.Port == null)
+ 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();
+
+ if (cookie.Domain == "")
+ cookie.Domain = uri.Host;
+
+ cookieCollection.Add (cookie);
+ }
+
+ void SetCookie2 (string cookies_str)
+ {
+ string [] cookies = cookies_str.Split (',');
+
+ foreach (string cookie_str in cookies)
+ SetCookie (cookie_str);
+ }
+ }
+}
+