-//\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)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Collections;
+using System.Globalization;
+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;
+ CookieContainer cookieContainer;
+
+ bool disposed = false;
+ Stream stream;
+
+ // Constructors
+
+ internal HttpWebResponse (Uri uri, string method, WebConnectionData data, CookieContainer container)
+ {
+ this.uri = uri;
+ this.method = method;
+ webHeaders = data.Headers;
+ version = data.Version;
+ statusCode = (HttpStatusCode) data.StatusCode;
+ statusDescription = data.StatusDescription;
+ stream = data.stream;
+ if (container != null) {
+ this.cookieContainer = container;
+ FillCookies ();
+ }
+ }
+
+ 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 ();
+ string h = webHeaders ["Content-Encoding"];
+ return h != null ? h : "";
+ }
+ }
+
+ 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
+#if !NET_2_0
+ public override int GetHashCode ()
+ {
+ CheckDisposed ();
+ return base.GetHashCode ();
+ }
+#endif
+
+ public string GetResponseHeader (string headerName)
+ {
+ CheckDisposed ();
+ string value = webHeaders [headerName];
+ return (value != null) ? value : "";
+ }
+
+ internal void ReadAll ()
+ {
+ WebConnectionStream wce = stream as WebConnectionStream;
+ if (wce == null)
+ return;
+
+ try {
+ wce.ReadAll ();
+ } catch {}
+ }
+
+ public override Stream GetResponseStream ()
+ {
+ CheckDisposed ();
+ if (stream == null)
+ return Stream.Null;
+ 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);
+ }
+
+#if !NET_2_0
+ protected virtual
+#endif
+ 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 [] values = webHeaders.GetValues ("Set-Cookie");
+ if (values != null) {
+ foreach (string va in values)
+ SetCookie (va);
+ }
+
+ values = webHeaders.GetValues ("Set-Cookie2");
+ if (values != null) {
+ foreach (string va in values)
+ SetCookie2 (va);
+ }
+ }
+
+ void SetCookie (string header)
+ {
+ string name, val;
+ Cookie cookie = null;
+ CookieParser parser = new CookieParser (header);
+
+ while (parser.GetNextNameValue (out name, out val)) {
+ if ((name == null || name == "") && cookie == null)
+ continue;
+
+ if (cookie == null) {
+ cookie = new Cookie (name, val);
+ continue;
+ }
+
+ name = name.ToUpper ();
+ switch (name) {
+ case "COMMENT":
+ if (cookie.Comment == null)
+ cookie.Comment = val;
+ break;
+ case "COMMENTURL":
+ if (cookie.CommentUri == null)
+ cookie.CommentUri = new Uri (val);
+ break;
+ case "DISCARD":
+ cookie.Discard = true;
+ break;
+ case "DOMAIN":
+ if (cookie.Domain == "")
+ cookie.Domain = val;
+ break;
+ case "MAX-AGE": // RFC Style Set-Cookie2
+ if (cookie.Expires == DateTime.MinValue) {
+ try {
+ cookie.Expires = cookie.TimeStamp.AddSeconds (UInt32.Parse (val));
+ } catch {}
+ }
+ break;
+ case "EXPIRES": // Netscape Style Set-Cookie
+ if (cookie.Expires != DateTime.MinValue)
+ break;
+ try {
+ cookie.Expires = DateTime.ParseExact (val, "r", CultureInfo.InvariantCulture);
+ } catch {
+ try {
+ cookie.Expires = DateTime.ParseExact (val,
+ "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
+ CultureInfo.InvariantCulture);
+ } catch {
+ cookie.Expires = DateTime.Now.AddDays (1);
+ }
+ }
+ break;
+ case "PATH":
+ cookie.Path = val;
+ break;
+ case "PORT":
+ if (cookie.Port == null)
+ cookie.Port = val;
+ break;
+ case "SECURE":
+ cookie.Secure = true;
+ break;
+ case "VERSION":
+ try {
+ cookie.Version = (int) UInt32.Parse (val);
+ } catch {}
+ break;
+ }
+ }
+
+ if (cookieCollection == null)
+ cookieCollection = new CookieCollection ();
+
+ if (cookie.Domain == "")
+ cookie.Domain = uri.Host;
+
+ cookieCollection.Add (cookie);
+ if (cookieContainer != null)
+ cookieContainer.Add (uri, cookie);
+ }
+
+ void SetCookie2 (string cookies_str)
+ {
+ string [] cookies = cookies_str.Split (',');
+
+ foreach (string cookie_str in cookies)
+ SetCookie (cookie_str);
+ }
+ }
+
+ class CookieParser {
+ string header;
+ int pos;
+ int length;
+
+ public CookieParser (string header) : this (header, 0)
+ {
+ }
+
+ public CookieParser (string header, int position)
+ {
+ this.header = header;
+ this.pos = position;
+ this.length = header.Length;
+ }
+
+ public bool GetNextNameValue (out string name, out string val)
+ {
+ name = null;
+ val = null;
+
+ if (pos >= length)
+ return false;
+
+ name = GetCookieName ();
+ if (pos < header.Length && header [pos] == '=') {
+ pos++;
+ val = GetCookieValue ();
+ }
+
+ if (pos < length && header [pos] == ';')
+ pos++;
+
+ return true;
+ }
+
+ string GetCookieName ()
+ {
+ int k = pos;
+ while (k < length && Char.IsWhiteSpace (header [k]))
+ k++;
+
+ int begin = k;
+ while (k < length && header [k] != ';' && header [k] != '=')
+ k++;
+
+ pos = k;
+ return header.Substring (begin, k - begin).Trim ();
+ }
+
+ string GetCookieValue ()
+ {
+ if (pos >= length)
+ return null;
+
+ int k = pos;
+ while (k < length && Char.IsWhiteSpace (header [k]))
+ k++;
+
+ int begin;
+ if (header [k] == '"'){
+ int j;
+ begin = ++k;
+
+ while (k < length && header [k] != '"')
+ k++;
+
+ for (j = k; j < length && header [j] != ';'; j++)
+ ;
+ pos = j;
+ } else {
+ begin = k;
+ while (k < length && header [k] != ';')
+ k++;
+ pos = k;
+ }
+
+ return header.Substring (begin, k - begin).Trim ();
+ }
+ }
+}
+