2 // System.Net.HttpWebResponse
5 // Lawrence Pit (loz@cable.a2000.nl)
10 using System.Runtime.Serialization;
15 public class HttpWebResponse : WebResponse, ISerializable, IDisposable
18 private WebHeaderCollection webHeaders;
19 private CookieCollection cookieCollection = null;
20 private string method = null;
21 private Version version = null;
22 private HttpStatusCode statusCode;
23 private string statusDescription = null;
25 private Stream responseStream;
26 private bool disposed = false;
30 internal HttpWebResponse (Uri uri, string method, Stream responseStream)
32 Text.StringBuilder value = null;
35 string[] protocol, header;
39 this.responseStream = responseStream;
40 this.webHeaders = new WebHeaderCollection();
42 line = ReadHttpLine(responseStream);
43 protocol = line.Split (' ');
45 switch (protocol[0]) {
47 this.version = HttpVersion.Version10;
50 this.version = HttpVersion.Version11;
53 throw new WebException ("Unrecognized HTTP Version");
56 this.statusCode = (HttpStatusCode) Int32.Parse (protocol[1]);
57 while ((line = ReadHttpLine(responseStream)).Length != 0) {
58 if (!Char.IsWhiteSpace (line[0])) { // new header
59 header = line.Split (new char[] {':'}, 2);
60 if (header.Length != 2)
61 throw new WebException ("Bad HTTP Header");
62 if (last != null) { // not the first header
63 if (last.Equals ("Set-Cookie"))
64 SetCookie (value.ToString());
65 else if (last.Equals ("Set-Cookie2"))
66 SetCookie2 (value.ToString());
67 else //don't save Set-Cookie headers
68 this.webHeaders[last] = value.ToString();
71 value = new Text.StringBuilder (header[1].Trim());
74 value.Append (line.Trim());
77 this.webHeaders[last] = value.ToString(); // otherwise we miss the last header
80 protected HttpWebResponse (SerializationInfo serializationInfo, StreamingContext streamingContext)
82 throw new NotSupportedException ();
87 public string CharacterSet {
88 // Content-Type = "Content-Type" ":" media-type
89 // media-type = type "/" subtype *( ";" parameter )
90 // parameter = attribute "=" value
91 // 3.7.1. default is ISO-8859-1
94 string contentType = ContentType;
95 if (contentType == null)
97 string val = contentType.ToLower ();
98 int pos = val.IndexOf ("charset=");
102 int pos2 = val.IndexOf (';', pos);
104 ? contentType.Substring (pos)
105 : contentType.Substring (pos, pos2 - pos);
112 public string ContentEncoding {
114 try { return webHeaders ["Content-Encoding"]; }
115 finally { CheckDisposed (); }
119 public override long ContentLength {
122 return Int64.Parse (webHeaders ["Content-Length"]);
123 } catch (Exception) {
131 public override string ContentType {
133 try { return webHeaders ["Content-Type"]; }
134 finally { CheckDisposed (); }
138 public CookieCollection Cookies {
142 if (cookieCollection == null)
143 cookieCollection = new CookieCollection ();
144 return cookieCollection;
148 // ?? don't understand how you can set cookies on a response.
149 throw new NotSupportedException ();
153 public override WebHeaderCollection Headers {
160 public DateTime LastModified {
164 string dtStr = webHeaders ["Last-Modified"];
165 return MonoHttpDate.Parse (dtStr);
166 } catch (Exception) {
172 public string Method {
179 public Version ProtocolVersion {
186 public override Uri ResponseUri {
193 public string Server {
196 return webHeaders ["Server"];
203 public HttpStatusCode StatusCode {
210 public string StatusDescription {
213 return statusDescription;
219 public override int GetHashCode ()
222 return base.GetHashCode ();
228 public string GetResponseHeader (string headerName)
231 return webHeaders [headerName];
237 public override Stream GetResponseStream ()
240 if (method.Equals ("HEAD")) // see par 4.3 & 9.4
242 return responseStream;
249 void ISerializable.GetObjectData (SerializationInfo serializationInfo,
250 StreamingContext streamingContext)
253 throw new NotImplementedException ();
264 public override void Close ()
266 ((IDisposable) this).Dispose ();
269 void IDisposable.Dispose ()
272 GC.SuppressFinalize (this);
275 protected virtual void Dispose (bool disposing)
279 this.disposed = true;
282 // release managed resources
285 cookieCollection = null;
288 // statusCode = null;
289 statusDescription = null;
292 // release unmanaged resources
293 Stream stream = responseStream;
294 responseStream = null;
296 stream.Close (); // also closes webRequest
299 private void CheckDisposed ()
302 throw new ObjectDisposedException (GetType ().FullName);
305 private static string ReadHttpLine (Stream stream)
307 Text.StringBuilder line = new Text.StringBuilder();
308 byte last = (byte)'\n';
309 bool read_last = false;
310 byte[] buf = new byte[1]; // one at a time to not snarf too much
312 while (stream.Read (buf, 0, buf.Length) != 0) {
313 if (buf[0] == '\r') {
314 if ((last = (byte)stream.ReadByte ()) == '\n') // headers; not at EOS
319 line.Append (Convert.ToChar(buf[0]));
321 line.Append (Convert.ToChar (last));
326 return line.ToString();
329 private void SetCookie (string cookie_str)
331 string[] parts = null;
332 Collections.Queue options = null;
333 Cookie cookie = null;
335 options = new Collections.Queue (cookie_str.Split (';'));
336 parts = ((string)options.Dequeue()).Split ('='); // NAME=VALUE must be first
338 cookie = new Cookie (parts[0], parts[1]);
340 while (options.Count > 0) {
341 parts = ((string)options.Dequeue()).Split ('=');
342 switch (parts[0].ToUpper()) { // cookie options are case-insensitive
344 if (cookie.Comment == null)
345 cookie.Comment = parts[1];
348 if (cookie.CommentUri == null)
349 cookie.CommentUri = new Uri(parts[1]);
352 cookie.Discard = true;
355 if (cookie.Domain == null)
356 cookie.Domain = parts[1];
358 case "MAX-AGE": // RFC Style Set-Cookie2
359 if (cookie.Expires == DateTime.MinValue)
360 cookie.Expires = cookie.TimeStamp.AddSeconds (Int32.Parse (parts[1]));
362 case "EXPIRES": // Netscape Style Set-Cookie
363 if (cookie.Expires == DateTime.MinValue)
364 cookie.Expires = DateTime.Parse (parts[1]);
367 if (cookie.Path == null)
368 cookie.Path = parts[1];
371 if (cookie.Port == null)
372 cookie.Port = parts[1];
375 cookie.Secure = true;
378 cookie.Version = Int32.Parse (parts[1]);
383 if (cookieCollection == null)
384 cookieCollection = new CookieCollection();
386 if (cookie.Domain == null)
387 cookie.Domain = uri.Host;
389 cookieCollection.Add (cookie);
392 private void SetCookie2 (string cookies_str)
394 string[] cookies = cookies_str.Split (',');
396 foreach (string cookie_str in cookies)
397 SetCookie (cookie_str);