// Authors:
// Lawrence Pit (loz@cable.a2000.nl)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Daniel Nauck (dna(at)mono-project(dot)de)
//
// (c) 2002 Lawrence Pit
// (c) 2003 Ximian, Inc. (http://www.ximian.com)
+// (c) 2008 Daniel Nauck
//
//
//
using System;
+using System.Collections;
using System.Globalization;
using System.IO;
using System.Net.Sockets;
using System.Runtime.Serialization;
using System.Text;
+#if NET_2_0
+using System.IO.Compression;
+#endif
namespace System.Net
{
Version version;
HttpStatusCode statusCode;
string statusDescription;
- long contentLength = -1;
+ long contentLength;
string contentType;
+ CookieContainer cookie_container;
- bool disposed = false;
+ bool disposed;
Stream stream;
// Constructors
- internal HttpWebResponse (Uri uri, string method, WebConnectionData data, bool cookiesSet)
+ internal HttpWebResponse (Uri uri, string method, WebConnectionData data, CookieContainer container)
{
this.uri = uri;
this.method = method;
statusCode = (HttpStatusCode) data.StatusCode;
statusDescription = data.StatusDescription;
stream = data.stream;
- if (cookiesSet) {
+ contentLength = -1;
+
+ try {
+ string cl = webHeaders ["Content-Length"];
+#if NET_2_0
+ if (String.IsNullOrEmpty (cl) || !Int64.TryParse (cl, out contentLength))
+ contentLength = -1;
+#else
+ if (cl != null && cl != String.Empty)
+ contentLength = (long) UInt64.Parse (cl);
+#endif
+ } catch (Exception) {
+ contentLength = -1;
+ }
+
+ if (container != null) {
+ this.cookie_container = container;
FillCookies ();
- } else if (webHeaders != null) {
- webHeaders.RemoveInternal ("Set-Cookie");
- webHeaders.RemoveInternal ("Set-Cookie2");
}
+#if NET_2_0
+ string content_encoding = webHeaders ["Content-Encoding"];
+ if (content_encoding == "gzip" && (data.request.AutomaticDecompression & DecompressionMethods.GZip) != 0)
+ stream = new GZipStream (stream, CompressionMode.Decompress);
+ else if (content_encoding == "deflate" && (data.request.AutomaticDecompression & DecompressionMethods.Deflate) != 0)
+ stream = new DeflateStream (stream, CompressionMode.Decompress);
+#endif
}
+#if NET_2_0
+ [Obsolete ("Serialization is obsoleted for this type", false)]
+#endif
protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
{
SerializationInfo info = serializationInfo;
// parameter = attribute "=" value
// 3.7.1. default is ISO-8859-1
get {
- CheckDisposed ();
string contentType = ContentType;
if (contentType == null)
return "ISO-8859-1";
}
public string ContentEncoding {
- get {
+ get {
CheckDisposed ();
- return webHeaders ["Content-Encoding"];
+ 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"];
}
public CookieCollection Cookies {
- get {
+ get {
CheckDisposed ();
-
if (cookieCollection == null)
cookieCollection = new CookieCollection ();
return cookieCollection;
}
public override WebHeaderCollection Headers {
- get {
+ get {
+#if ONLY_1_1
CheckDisposed ();
+#endif
return webHeaders;
}
}
+
+#if NET_2_0
+ static Exception GetMustImplement ()
+ {
+ return new NotImplementedException ();
+ }
+
+ [MonoTODO]
+ public override bool IsMutuallyAuthenticated
+ {
+ get {
+ throw GetMustImplement ();
+ }
+ }
+#endif
public DateTime LastModified {
get {
}
public string Method {
- get {
+ get {
CheckDisposed ();
return method;
}
}
public Version ProtocolVersion {
- get {
+ get {
CheckDisposed ();
return version;
}
}
public override Uri ResponseUri {
- get {
+ get {
CheckDisposed ();
return uri;
}
}
public string Server {
- get {
+ get {
CheckDisposed ();
return webHeaders ["Server"];
}
}
public HttpStatusCode StatusCode {
- get {
- CheckDisposed ();
+ get {
return statusCode;
}
}
public string StatusDescription {
- get {
+ get {
CheckDisposed ();
return statusDescription;
}
}
// Methods
-
+#if !NET_2_0
public override int GetHashCode ()
{
- CheckDisposed ();
return base.GetHashCode ();
}
+#endif
public string GetResponseHeader (string headerName)
{
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 ();
void ISerializable.GetObjectData (SerializationInfo serializationInfo,
StreamingContext streamingContext)
+ {
+ GetObjectData (serializationInfo, streamingContext);
+ }
+
+#if NET_2_0
+ protected override
+#endif
+ void GetObjectData (SerializationInfo serializationInfo,
+ StreamingContext streamingContext)
{
SerializationInfo info = serializationInfo;
info.AddValue ("cookieCollection", cookieCollection);
info.AddValue ("version", version);
info.AddValue ("statusCode", statusCode);
- }
-
+ }
// Cleaning up stuff
Dispose (true);
GC.SuppressFinalize (this);
}
-
- protected virtual void Dispose (bool disposing)
+
+#if !NET_2_0
+ protected virtual
+#endif
+ void Dispose (bool disposing)
{
if (this.disposed)
return;
if (disposing) {
// release managed resources
uri = null;
+#if !NET_2_0
webHeaders = null;
+#endif
cookieCollection = null;
method = null;
version = null;
// release unmanaged resources
Stream st = stream;
stream = null;
- if (st != null) {
- WebConnectionStream wce = st as WebConnectionStream;
- if (wce != null) {
- try {
- wce.ReadAll ();
- } catch {}
- }
+ if (st != null)
st.Close ();
- }
}
private void CheckDisposed ()
SetCookie2 (va);
}
}
-
+
void SetCookie (string header)
{
- string [] name_values = header.Trim ().Split (';');
- int length = name_values.Length;
+ string name, val;
Cookie cookie = null;
- int pos;
- for (int i = 0; i < length; i++) {
- pos = 0;
- string name_value = name_values [i].Trim ();
- string name = GetCookieName (name_value, name_value.Length, ref pos);
- string value = GetCookieValue (name_value, name_value.Length, ref pos);
+ 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, value);
+ cookie = new Cookie (name, val);
continue;
}
switch (name) {
case "COMMENT":
if (cookie.Comment == null)
- cookie.Comment = value;
+ cookie.Comment = val;
break;
case "COMMENTURL":
if (cookie.CommentUri == null)
- cookie.CommentUri = new Uri (value);
+ cookie.CommentUri = new Uri (val);
break;
case "DISCARD":
cookie.Discard = true;
break;
case "DOMAIN":
if (cookie.Domain == "")
- cookie.Domain = value;
+ cookie.Domain = val;
break;
+#if NET_2_0
+ case "HTTPONLY":
+ cookie.HttpOnly = true;
+ break;
+#endif
case "MAX-AGE": // RFC Style Set-Cookie2
- if (cookie.Expires == DateTime.MinValue)
- cookie.Expires = cookie.TimeStamp.AddSeconds (Int32.Parse (value));
+ 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 (value, "r", CultureInfo.InvariantCulture);
- } catch {
- try {
- cookie.Expires = DateTime.ParseExact (value,
- "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
- CultureInfo.InvariantCulture);
- } catch {
- cookie.Expires = DateTime.Now.AddDays (1);
- }
- }
+
+ cookie.Expires = TryParseCookieExpires (val);
break;
case "PATH":
- cookie.Path = value;
+ cookie.Path = val;
break;
case "PORT":
if (cookie.Port == null)
- cookie.Port = value;
+ cookie.Port = val;
break;
case "SECURE":
cookie.Secure = true;
break;
case "VERSION":
- cookie.Version = Int32.Parse (value);
+ try {
+ cookie.Version = (int) UInt32.Parse (val);
+ } catch {}
break;
}
}
cookie.Domain = uri.Host;
cookieCollection.Add (cookie);
+ if (cookie_container != null)
+ cookie_container.Add (uri, cookie);
}
void SetCookie2 (string cookies_str)
SetCookie (cookie_str);
}
- static string GetCookieValue (string str, int length, ref int i)
+ string[] cookieExpiresFormats =
+ new string[] { "r",
+ "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
+ "ddd, dd'-'MMM'-'yy HH':'mm':'ss 'GMT'" };
+
+ DateTime TryParseCookieExpires (string value)
{
- if (i >= length)
- return null;
+ if (value == null || value.Length == 0)
+ return DateTime.MinValue;
+
+ for (int i = 0; i < cookieExpiresFormats.Length; i++)
+ {
+ try {
+ DateTime cookieExpiresUtc = DateTime.ParseExact (value, cookieExpiresFormats [i], CultureInfo.InvariantCulture);
+
+ //convert UTC/GMT time to local time
+#if NET_2_0
+ cookieExpiresUtc = DateTime.SpecifyKind (cookieExpiresUtc, DateTimeKind.Utc);
+ return TimeZone.CurrentTimeZone.ToLocalTime (cookieExpiresUtc);
+#else
+ //DateTime.Kind is only available on .NET 2.0, so do some calculation
+ TimeSpan localOffset = TimeZone.CurrentTimeZone.GetUtcOffset (cookieExpiresUtc.Date);
+ return cookieExpiresUtc.Add (localOffset);
+#endif
+ } catch {}
+ }
- int k = i;
- while (k < length && Char.IsWhiteSpace (str [k]))
+ //If we can't parse Expires, use cookie as session cookie (expires is DateTime.MinValue)
+ return DateTime.MinValue;
+ }
+ }
+
+ 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 && str [k] != ';')
+ while (k < length && header [k] != ';' && header [k] != '=')
k++;
- i = k;
- return str.Substring (begin, i - begin).Trim ();
+ pos = k;
+ return header.Substring (begin, k - begin).Trim ();
}
- static string GetCookieName (string str, int length, ref int i)
+ string GetCookieValue ()
{
- if (i >= length)
+ if (pos >= length)
return null;
- int k = i;
- while (k < length && Char.IsWhiteSpace (str [k]))
+ int k = pos;
+ while (k < length && Char.IsWhiteSpace (header [k]))
k++;
- int begin = k;
- while (k < length && str [k] != ';' && str [k] != '=')
- k++;
-
- i = k + 1;
- return str.Substring (begin, k - begin).Trim ();
+ 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 ();
}
- }
+ }
}