Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System / net / System / Net / HttpWebResponse.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpWebResponse.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 namespace System.Net {
8     using System.IO;
9     using System.IO.Compression;
10     using System.Runtime.Serialization;
11     using System.ComponentModel;
12     using System.Globalization;
13     using System.Security.Cryptography.X509Certificates;
14     using System.Security.Permissions;
15     using System.Diagnostics;
16     using System.Diagnostics.CodeAnalysis;
17     using System.Net.WebSockets;
18
19     //
20     // HttpWebResponse - Handles retrival of HTTP Response headers, und Data reads.
21     //
22
23     /// <devdoc>
24     ///    <para>
25     ///    An HTTP-specific implementation of the
26     ///    <see cref='System.Net.WebResponse'/> class.
27     /// </para>
28     /// </devdoc>
29     [Serializable]
30     public class HttpWebResponse : WebResponse, ISerializable
31     {
32         // response Uri generated by the request.
33         private Uri m_Uri;
34         // response Verb gernated by the request
35         private KnownHttpVerb m_Verb;
36         // response values
37         private HttpStatusCode m_StatusCode;
38         private string m_StatusDescription;
39         // ConnectStream - for reading actual data
40         private Stream m_ConnectStream;
41         // For the rare case of Post -> Get redirect where we need to re-process the response.
42         private CoreResponseData m_CoreResponseData;
43
44         private WebHeaderCollection m_HttpResponseHeaders;
45
46         // Content Length needed for symantics, -1 if chunked
47         private long m_ContentLength;
48
49         // for which response ContentType we will look for and parse the CharacterSet
50         private string m_MediaType;
51         private string m_CharacterSet = null;
52
53         private bool m_IsVersionHttp11;
54
55 #if !FEATURE_PAL
56         // server certificate for secure connections
57         internal X509Certificate m_Certificate;
58 #endif // !FEATURE_PAL
59
60         private CookieCollection m_cookies;
61         private bool m_disposed; // = false;
62         private bool m_propertiesDisposed;
63         private bool m_UsesProxySemantics;
64         private bool m_IsMutuallyAuthenticated;
65
66         private bool m_IsWebSocketResponse;
67         private string m_ConnectionGroupName;
68         private Stream m_WebSocketConnectionStream = null;
69
70         internal bool IsWebSocketResponse
71         {
72             get { return m_IsWebSocketResponse; }
73             set { m_IsWebSocketResponse = value; }
74         }
75
76         internal string ConnectionGroupName
77         {
78             get { return m_ConnectionGroupName; }
79             set { m_ConnectionGroupName = value; }
80         }
81
82         //
83         // Internal Access to the Response Stream,
84         //  public method is GetResponseStream
85         //
86         internal Stream ResponseStream {
87             get {
88                 return m_ConnectStream;
89             }
90             set {
91                 m_ConnectStream = value;
92             }
93         }
94
95         internal CoreResponseData CoreResponseData
96         {
97             get { return m_CoreResponseData; }
98         }
99
100         //
101         public override bool IsMutuallyAuthenticated {
102             get {
103                 CheckDisposed();
104                 return m_IsMutuallyAuthenticated;
105             }
106         }
107         internal bool InternalSetIsMutuallyAuthenticated {
108             set {
109                 m_IsMutuallyAuthenticated = value;
110             }
111         }
112
113         /// <devdoc>
114         ///    <para>[To be supplied.]</para>
115         /// </devdoc>
116         public virtual CookieCollection Cookies {
117             get {
118                 CheckDisposed();
119                 if (m_cookies == null) {
120                     m_cookies = new CookieCollection();
121                 }
122                 return m_cookies;
123             }
124             set {
125                 CheckDisposed();
126                 m_cookies = value;
127             }
128         }
129
130         // retreives response header object
131         /// <devdoc>
132         ///    <para>
133         ///       Gets
134         ///       the headers associated with this response from the server.
135         ///    </para>
136         /// </devdoc>
137         public override WebHeaderCollection Headers {
138             get {
139                 CheckDisposed();
140                 return m_HttpResponseHeaders;
141             }
142         }
143
144         // For portability only
145         public override bool SupportsHeaders {
146             get {
147                 return true;
148             }
149         }
150
151         // ContentLength, -1 indicates unknown value
152         /// <devdoc>
153         ///    <para>
154         ///       Gets the lenght of the content returned by the request.
155         ///    </para>
156         /// </devdoc>
157         public override long ContentLength {
158             get {
159                 CheckDisposed();
160                 return m_ContentLength;
161             }
162         }
163
164         /// <devdoc>
165         ///    <para>
166         ///       Gets the
167         ///       method used to encode the body of the response.
168         ///    </para>
169         /// </devdoc>
170         public String ContentEncoding {
171             get {
172                 CheckDisposed();
173                 string contentEncoding = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding];
174                 return contentEncoding == null ? string.Empty : contentEncoding;
175             }
176         }
177
178         // Returns the Content-Type of the response.
179
180         /// <devdoc>
181         ///    <para>
182         ///       Gets the content type of the
183         ///       response.
184         ///    </para>
185         /// </devdoc>
186         public override string ContentType {
187             get {
188                 CheckDisposed();
189                 string contentType = m_HttpResponseHeaders.ContentType;
190                 return contentType == null ? string.Empty : contentType;
191             }
192         }
193
194
195         /// <devdoc>
196         ///    <para>[To be supplied.]</para>
197         /// </devdoc>
198         public string CharacterSet {
199             get {
200                 CheckDisposed();
201                 string contentType = m_HttpResponseHeaders.ContentType;
202
203                 if (m_CharacterSet == null && !ValidationHelper.IsBlankString(contentType)) {
204
205                     //sets characterset so the branch is never executed again.
206                     m_CharacterSet = String.Empty;
207
208                     //first string is the media type
209                     string srchString = contentType.ToLower(CultureInfo.InvariantCulture);
210
211                     //media subtypes of text type has a default as specified by rfc 2616
212                     if (srchString.Trim().StartsWith("text/")) {
213                         m_CharacterSet = "ISO-8859-1";
214                     }
215
216                     //one of the parameters may be the character set
217                     //there must be at least a mediatype for this to be valid
218                     int i = srchString.IndexOf(";");
219                     if (i > 0) {
220
221                         //search the parameters
222                         while ((i = srchString.IndexOf("charset",i)) >= 0){
223
224                             i+=7;
225
226                             //make sure the word starts with charset
227                             if (srchString[i-8] == ';' || srchString[i-8] == ' '){
228
229                                 //skip whitespace
230                                 while (i < srchString.Length && srchString[i] == ' ')
231                                     i++;
232
233                                 //only process if next character is '='
234                                 //and there is a character after that
235                                 if (i < srchString.Length - 1 && srchString[i] == '=') {
236                                    i++;
237
238                                    //get and trim character set substring
239                                    int j = srchString.IndexOf(';',i);
240                                    //In the past we used
241                                    //Substring(i, j). J is the offset not the length
242                                    //the qfe is to fix the second parameter so that this it is the
243                                    //length. since j points to the next ; the operation j -i
244                                    //gives the length of the charset
245                                    if (j>i)
246                                        m_CharacterSet = contentType.Substring(i,j - i).Trim();
247                                    else
248                                        m_CharacterSet = contentType.Substring(i).Trim();
249
250                                    //done
251                                    break;
252                                 }
253                             }
254                         }
255                     }
256                 }
257                 return m_CharacterSet;
258             }
259         }
260
261         /// <devdoc>
262         ///    <para>
263         ///       Gets the name of the server that sent the response.
264         ///    </para>
265         /// </devdoc>
266         public string Server {
267             get {
268                 CheckDisposed();
269                 string server = m_HttpResponseHeaders.Server;
270                 return server == null ? string.Empty : server;
271             }
272         }
273
274         /// <devdoc>
275         ///    <para>
276         ///       Gets the last
277         ///       date and time that the content of the response was modified.
278         ///    </para>
279         /// </devdoc>
280         public  DateTime LastModified {
281             get {
282                 CheckDisposed();
283
284                 string lastmodHeaderValue = m_HttpResponseHeaders.LastModified;
285
286                 if (lastmodHeaderValue == null) {
287                     return DateTime.Now;
288                 }
289                 return HttpProtocolUtils.string2date(lastmodHeaderValue);
290             }
291         }
292
293         // returns StatusCode
294         /// <devdoc>
295         ///    <para>
296         ///       Gets
297         ///       a number indicating the status of the response.
298         ///    </para>
299         /// </devdoc>
300         public virtual HttpStatusCode StatusCode {
301             get {
302                 CheckDisposed();
303                 return m_StatusCode;
304             }
305         }
306
307         // returns StatusDescription
308         /// <devdoc>
309         ///    <para>
310         ///       Gets the status description returned with the response.
311         ///    </para>
312         /// </devdoc>
313         public virtual string StatusDescription {
314             get {
315                 CheckDisposed();
316                 return m_StatusDescription;
317             }
318         }
319
320         // HTTP Version
321         /// <devdoc>
322         ///    <para>
323         ///       Gets
324         ///       the version of the HTTP protocol used in the response.
325         ///    </para>
326         /// </devdoc>
327         public Version ProtocolVersion {
328             get {
329                 CheckDisposed();
330                 return m_IsVersionHttp11 ? HttpVersion.Version11 : HttpVersion.Version10;
331             }
332         }
333
334
335         internal bool KeepAlive {
336             get {
337                 //
338                 // QFE  - DevDiv bug: 37757
339                 // If there is proxy involved, independen of the Http Version, we should honor the
340                 // proxy indicated Proxy-Connection header value.
341                 // This header value is not RFC mandated, but is a legacy from Netscape documentations.
342                 // It indicates that the proxy wants to keep the connection.
343                 // Functionally it is equivalent of a Keep-Alive AND/OR Connection header.
344                 //
345                 // The absence of this check will result in HTTP/1.0 responsen be considered to be not
346                 // Keeping the connection alive.
347                 //
348                 // This will result in a state mismatch between the connection pool and HttpWebRequest object
349                 // when the decision to drain the connection and putting it back to the idle pool is made.
350                 //
351                 if (m_UsesProxySemantics)
352                 {
353                     string proxyConnectionHeader = Headers[HttpKnownHeaderNames.ProxyConnection];
354                     if (proxyConnectionHeader != null)
355                     {
356                         return proxyConnectionHeader.ToLower(CultureInfo.InvariantCulture).IndexOf("close") < 0 || 
357                                proxyConnectionHeader.ToLower(CultureInfo.InvariantCulture).IndexOf("keep-alive") >= 0;
358                     }
359                 }
360
361                 string connectionHeader = Headers[HttpKnownHeaderNames.Connection];
362                 if (connectionHeader != null) 
363                 {
364                     connectionHeader = connectionHeader.ToLower(CultureInfo.InvariantCulture);
365                 }
366
367                 if (ProtocolVersion == HttpVersion.Version10) 
368                 {
369                     // An HTTP/1.0 response is keep-alive if it has a connection: keep-alive header
370                     return (connectionHeader != null && 
371                             connectionHeader.IndexOf("keep-alive") >= 0);
372                 }
373                 else if (ProtocolVersion >= HttpVersion.Version11)
374                 {
375                     // An HTTP/1.1 response is keep-alive if it DOESN'T have a connection: close header, or if it
376                     // also has a connection: keep-alive header
377                     return (connectionHeader == null ||
378                             connectionHeader.IndexOf("close") < 0 ||
379                             connectionHeader.IndexOf("keep-alive") >= 0);
380                 }
381
382                 return false;
383             }
384         }
385
386
387         /*++
388
389             ResponseStream - Return the response stream.
390
391             This property returns the response stream for this response. The
392             response stream will do de-chunking, etc. as needed.
393
394             Input: Nothing. Property is readonly.
395
396             Returns: Response stream for response.
397
398         --*/
399
400
401         /// <devdoc>
402         ///    <para>Gets the stream used for reading the body of the response from the
403         ///       server.</para>
404         /// </devdoc>
405         public override Stream GetResponseStream() {
406             if(Logging.On)Logging.Enter(Logging.Web, this, "GetResponseStream", "");
407             CheckDisposed();
408             if(Logging.On)Logging.PrintInfo(Logging.Web, "ContentLength="+m_ContentLength);
409
410             Stream result;
411             if (m_IsWebSocketResponse && m_StatusCode == HttpStatusCode.SwitchingProtocols) // HTTP 101
412             {
413                 if (this.m_WebSocketConnectionStream == null)
414                 {
415                     ConnectStream connectStream = m_ConnectStream as ConnectStream;
416                     GlobalLog.Assert(connectStream != null, "HttpWebResponse.m_ConnectStream should always be a ConnectStream in WebSocket cases.");
417                     GlobalLog.Assert(connectStream.Connection != null, "HttpWebResponse.m_ConnectStream.Connection should never be null in WebSocket cases.");
418                     this.m_WebSocketConnectionStream = new WebSocketConnectionStream(connectStream, this.ConnectionGroupName);
419                 }
420                 result = this.m_WebSocketConnectionStream;
421             }
422             else
423             {
424                 result = m_ConnectStream;
425             }
426             
427             if(Logging.On)Logging.Exit(Logging.Web, this, "GetResponseStream", result);
428             return result;
429         }
430
431         /*++
432
433             Close - Closes the Response after the use.
434
435             This causes the read stream to be closed.
436
437         --*/
438
439         public override void Close() {
440             if(Logging.On)Logging.Enter(Logging.Web, this, "Close", "");
441             if (!m_disposed)
442             {
443                 m_disposed = true;
444                 try
445                 {
446                     Stream stream = m_ConnectStream;
447                     ICloseEx icloseEx = stream as ICloseEx;
448                     if (icloseEx != null)
449                     {
450                         icloseEx.CloseEx(CloseExState.Normal /* | CloseExState.Silent */);
451                     }
452                     else if (stream != null)
453                     {
454                         stream.Close();
455                     }
456                 }
457                 finally
458                 {
459                     if (this.IsWebSocketResponse)
460                     {
461                         ConnectStream connectStream = m_ConnectStream as ConnectStream;
462                         if (connectStream != null && connectStream.Connection != null)
463                         {
464                             connectStream.Connection.ServicePoint.CloseConnectionGroup(ConnectionGroupName);
465                         }
466                     }
467                 }
468             }
469             if(Logging.On)Logging.Exit(Logging.Web, this, "Close", "");
470         }
471
472         // This method is only to be called by HttpWebRequest.Abort().
473         internal void Abort() {
474             Stream stream = m_ConnectStream;
475             ICloseEx icloseEx = stream as ICloseEx;
476             try
477             {
478                 if (icloseEx != null) {
479                     icloseEx.CloseEx(CloseExState.Abort);
480                 }
481                 else if (stream != null) {
482                     stream.Close();
483                 }
484             }
485             catch { }
486         }
487
488         [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", 
489             Justification = "The base class calls Close() to clean up m_ConnectStream")]
490         protected override void Dispose(bool disposing) {
491             if (!disposing) {
492                 return;
493             }
494             base.Dispose(true); // Calls Close()
495             m_propertiesDisposed = true;
496         }
497
498         //introduced for supporting design-time loading of System.Windows.dll
499         [Obsolete("This API supports the .NET Framework infrastructure and is not intended to be used directly from your code.", true)]
500         [EditorBrowsable(EditorBrowsableState.Never)]
501         public HttpWebResponse(){}
502
503         internal HttpWebResponse(Uri responseUri, KnownHttpVerb verb, CoreResponseData coreData, string mediaType, 
504             bool usesProxySemantics, DecompressionMethods decompressionMethod, 
505             bool isWebSocketResponse, string connectionGroupName) {
506             m_Uri                       = responseUri;
507             m_Verb                      = verb;
508             m_MediaType                 = mediaType;
509             m_UsesProxySemantics        = usesProxySemantics;
510
511             m_CoreResponseData          = coreData;
512             m_ConnectStream             = coreData.m_ConnectStream;
513             m_HttpResponseHeaders       = coreData.m_ResponseHeaders;
514             m_ContentLength             = coreData.m_ContentLength;
515             m_StatusCode                = coreData.m_StatusCode;
516             m_StatusDescription         = coreData.m_StatusDescription;
517             m_IsVersionHttp11           = coreData.m_IsVersionHttp11;
518
519             m_IsWebSocketResponse       = isWebSocketResponse;
520             m_ConnectionGroupName       = connectionGroupName;
521
522             //if the returned contentlength is zero, preemptively invoke calldone on the stream.
523             //this will wake up any pending reads.
524             if (m_ContentLength == 0 && m_ConnectStream is ConnectStream) {
525                 ((ConnectStream)m_ConnectStream).CallDone();
526             }
527
528             // handle Content-Location header, by combining it with the orginal request.
529             string contentLocation = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentLocation];
530
531             if (contentLocation != null) {
532                 try {
533                     m_Uri = new Uri(m_Uri, contentLocation);
534                 } catch (UriFormatException e) {
535                     GlobalLog.Assert("Exception on response Uri parsing.", e.ToString());
536                 }
537             }
538             // decompress responses by hooking up a final response Stream - only if user required it
539             if(decompressionMethod != DecompressionMethods.None) {
540                 string contentEncoding = m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding];
541                 if (contentEncoding != null){
542                     if(((decompressionMethod & DecompressionMethods.GZip) != 0) && 
543                         contentEncoding.IndexOf(HttpWebRequest.GZipHeader, StringComparison.CurrentCulture) != -1) {
544                         m_ConnectStream = new GZipWrapperStream(m_ConnectStream, CompressionMode.Decompress);
545                         m_ContentLength = -1; // unknown on compressed streams
546
547                         // Setting a response header after parsing will ruin the Common Header optimization.
548                         // This seems like a corner case.  ContentEncoding could be added as a common header, with a special
549                         // property allowing it to be nulled.
550                         m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null;
551                     }
552                     else if (((decompressionMethod & DecompressionMethods.Deflate) != 0) && 
553                         contentEncoding.IndexOf(HttpWebRequest.DeflateHeader, StringComparison.CurrentCulture) != -1) {
554                         m_ConnectStream = new DeflateWrapperStream(m_ConnectStream, CompressionMode.Decompress);
555                         m_ContentLength = -1; // unknown on compressed streams
556
557                         // Setting a response header after parsing will ruin the Common Header optimization.
558                         // This seems like a corner case.  ContentEncoding could be added as a common header, with a special
559                         // property allowing it to be nulled.
560                         m_HttpResponseHeaders[HttpKnownHeaderNames.ContentEncoding] = null;
561                     }
562                 }
563             }
564         }
565
566         //
567         // ISerializable constructor
568         //
569         /// <devdoc>
570         ///    <para>[To be supplied.]</para>
571         /// </devdoc>
572
573         [Obsolete("Serialization is obsoleted for this type.  http://go.microsoft.com/fwlink/?linkid=14202")]
574         protected HttpWebResponse(SerializationInfo serializationInfo, StreamingContext streamingContext):base(serializationInfo, streamingContext) {
575             m_HttpResponseHeaders   = (WebHeaderCollection)serializationInfo.GetValue("m_HttpResponseHeaders", typeof(WebHeaderCollection));
576             m_Uri                   = (Uri)serializationInfo.GetValue("m_Uri", typeof(Uri));
577 #if !FEATURE_PAL
578             m_Certificate           = (X509Certificate)serializationInfo.GetValue("m_Certificate", typeof(X509Certificate));
579 #endif // !FEATURE_PAL
580             Version version         = (Version)serializationInfo.GetValue("m_Version", typeof(Version));
581             m_IsVersionHttp11       = version.Equals(HttpVersion.Version11);
582             m_StatusCode            = (HttpStatusCode)serializationInfo.GetInt32("m_StatusCode");
583             m_ContentLength         = serializationInfo.GetInt64("m_ContentLength");
584             m_Verb                  = KnownHttpVerb.Parse(serializationInfo.GetString("m_Verb"));
585             m_StatusDescription     = serializationInfo.GetString("m_StatusDescription");
586             m_MediaType             = serializationInfo.GetString("m_MediaType");
587         }
588
589         //
590         // ISerializable method
591         //
592         /// <internalonly/>
593         [SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
594         [SecurityPermission(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter, SerializationFormatter=true)]
595         void ISerializable.GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
596         {
597             GetObjectData(serializationInfo, streamingContext);
598         }
599
600         //
601         // FxCop: provide a way for derived classes to access this method even if they reimplement ISerializable.
602         //
603
604         [SecurityPermission(SecurityAction.Demand, SerializationFormatter=true)]
605         protected override void GetObjectData(SerializationInfo serializationInfo, StreamingContext streamingContext)
606         {
607             //
608             // for now disregard streamingContext.
609             // just Add all the members we need to deserialize to construct
610             // the object at deserialization time
611             //
612             // the following runtime types already support serialization:
613             // Boolean, Char, SByte, Byte, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double, DateTime
614             // for the others we need to provide our own serialization
615             //
616             serializationInfo.AddValue("m_HttpResponseHeaders", m_HttpResponseHeaders, typeof(WebHeaderCollection));
617             serializationInfo.AddValue("m_Uri", m_Uri, typeof(Uri));
618 #if !FEATURE_PAL
619             serializationInfo.AddValue("m_Certificate", m_Certificate, typeof(X509Certificate));
620 #endif // !FEATURE_PAL
621             serializationInfo.AddValue("m_Version", ProtocolVersion, typeof(Version));
622             serializationInfo.AddValue("m_StatusCode", m_StatusCode);
623             serializationInfo.AddValue("m_ContentLength", m_ContentLength);
624             serializationInfo.AddValue("m_Verb", m_Verb.Name);
625             serializationInfo.AddValue("m_StatusDescription", m_StatusDescription);
626             serializationInfo.AddValue("m_MediaType", m_MediaType);
627             base.GetObjectData(serializationInfo, streamingContext);
628         }
629
630         /*++
631
632         Routine Description:
633
634             Gets response headers from parsed server response
635
636         Arguments:
637
638             headerName - HTTP header to search for matching header on.
639
640         Return Value:
641
642             string - contains the matched entry, if found
643
644         --*/
645         /// <devdoc>
646         ///    <para>
647         ///       Gets a specified header value returned with the response.
648         ///    </para>
649         /// </devdoc>
650         public string GetResponseHeader( string headerName ) {
651             CheckDisposed();
652
653             string headerValue = m_HttpResponseHeaders[headerName];
654
655             return ( (headerValue==null) ? String.Empty : headerValue );
656         }
657
658 #if HTTP_HEADER_EXTENSIONS_SUPPORTED
659         // searches for extension header in response
660         /// <devdoc>
661         ///    <para>[To be supplied.]</para>
662         /// </devdoc>
663         public string GetExtension(HttpExtension extension, string header) {
664             CheckDisposed();
665             return GetResponseHeader(header);
666         }
667 #endif
668
669         /*++
670
671             ResponseUri  - Gets the final Response Uri, that includes any
672              changes that may have transpired from the orginal Request
673
674             This property returns Uri for this WebResponse.
675
676             Input: Nothing.
677
678             Returns: Response Uri for response.
679
680                     read-only
681
682         --*/
683
684         /// <devdoc>
685         ///    <para>
686         ///       Gets the Uniform Resource Indentifier (Uri) of the resource that returned the
687         ///       response.
688         ///    </para>
689         /// </devdoc>
690         public override Uri ResponseUri {                               // read-only
691             get {
692                 CheckDisposed();
693                 return m_Uri;
694             }
695         }
696
697         /*
698             Accessor:   Method
699
700             Gets/Sets the http method of this request.
701             This method represents the Verb,
702             after any redirects
703
704             Returns: Method currently being used.
705
706
707         */
708         /// <devdoc>
709         ///    <para>
710         ///       Gets the value of the method used to return the response.
711         ///    </para>
712         /// </devdoc>
713         public virtual string Method {
714             get {
715                 CheckDisposed();
716                 return m_Verb.Name;
717             }
718         }
719
720         private void CheckDisposed() {
721             if (m_propertiesDisposed) {
722                 throw new ObjectDisposedException(this.GetType().FullName);
723             }
724         }
725     } // class HttpWebResponse
726
727     // transfer ICloseEx behavior to nested compound stream.
728     internal class GZipWrapperStream : GZipStream, ICloseEx, IRequestLifetimeTracker {
729
730         public GZipWrapperStream(Stream stream, CompressionMode mode) : base( stream, mode, false) {
731         }
732
733         void ICloseEx.CloseEx(CloseExState closeState) {
734             ICloseEx icloseEx = BaseStream as ICloseEx;
735             if (icloseEx != null) {
736                 // since the internal Close() of GZipStream just does Close on our base stream
737                 // we don't have to call it anymore at this point
738                 icloseEx.CloseEx(closeState);
739             }
740             else {
741                 Close();
742             }
743         }
744
745         public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
746
747             if (buffer==null) {
748                 throw new ArgumentNullException("buffer");
749             }
750             if (offset<0 || offset>buffer.Length) {
751                 throw new ArgumentOutOfRangeException("offset");
752             }
753             if (size<0 || size>buffer.Length-offset) {
754                 throw new ArgumentOutOfRangeException("size");
755             }
756
757             try{
758                 return base.BeginRead(buffer, offset, size, callback, state);
759             }
760             catch(Exception e){
761                 try{
762                     if (NclUtilities.IsFatal(e)) throw;
763                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
764                         Close();
765                     }
766                 }
767                 catch{
768                 }
769                 throw e;
770             }
771         }
772
773         public override int EndRead(IAsyncResult asyncResult) {
774
775             if (asyncResult==null) {
776                 throw new ArgumentNullException("asyncResult");
777             }
778
779             try{
780                 return base.EndRead(asyncResult);
781             }
782             catch(Exception e){
783                 try{
784                     if (NclUtilities.IsFatal(e)) throw;
785                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
786                         Close();
787                     }
788                 }
789                 catch{
790                 }
791                 throw e;
792             }
793         }
794
795         public override int Read(byte[] buffer, int offset, int size) {
796
797             if (buffer==null) {
798                 throw new ArgumentNullException("buffer");
799             }
800             if (offset<0 || offset>buffer.Length) {
801                 throw new ArgumentOutOfRangeException("offset");
802             }
803             if (size<0 || size>buffer.Length-offset) {
804                 throw new ArgumentOutOfRangeException("size");
805             }
806
807             try{
808                 return base.Read(buffer, offset, size);
809             }
810             catch(Exception e){
811                 try{
812                     if (NclUtilities.IsFatal(e)) throw;
813
814                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
815                         Close();
816                     }
817                 }
818                 catch{
819                 }
820                 throw e;
821             }
822         }
823
824         void IRequestLifetimeTracker.TrackRequestLifetime(long requestStartTimestamp)
825         {
826             IRequestLifetimeTracker stream = BaseStream as IRequestLifetimeTracker;
827             Debug.Assert(stream != null, "Wrapped stream must implement IRequestLifetimeTracker interface");
828             stream.TrackRequestLifetime(requestStartTimestamp);
829         }
830     }
831
832
833     internal class DeflateWrapperStream : DeflateStream, ICloseEx, IRequestLifetimeTracker {
834
835         public DeflateWrapperStream(Stream stream, CompressionMode mode) : base( stream, mode, false) {
836         }
837
838         void ICloseEx.CloseEx(CloseExState closeState) {
839             ICloseEx icloseEx = BaseStream as ICloseEx;
840             if (icloseEx != null) {
841                 // since the internal Close() of GZipStream just does Close on our base stream
842                 // we don't have to call it anymore at this point
843                 icloseEx.CloseEx(closeState);
844             }
845             else {
846                 Close();
847             }
848         }
849
850
851         public override IAsyncResult BeginRead(byte[] buffer, int offset, int size, AsyncCallback callback, Object state) {
852
853             if (buffer==null) {
854                 throw new ArgumentNullException("buffer");
855             }
856             if (offset<0 || offset>buffer.Length) {
857                 throw new ArgumentOutOfRangeException("offset");
858             }
859             if (size<0 || size>buffer.Length-offset) {
860                 throw new ArgumentOutOfRangeException("size");
861             }
862
863             try{
864                 return base.BeginRead(buffer, offset, size, callback, state);
865             }
866             catch(Exception e){
867                 try{
868                     if (NclUtilities.IsFatal(e)) throw;
869                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
870                         Close();
871                     }
872                 }
873                 catch{
874                 }
875                 throw e;
876             }
877         }
878
879         public override int EndRead(IAsyncResult asyncResult) {
880
881             if (asyncResult==null) {
882                 throw new ArgumentNullException("asyncResult");
883             }
884
885             try{
886                 return base.EndRead(asyncResult);
887             }
888             catch(Exception e){
889                 try{
890                     if (NclUtilities.IsFatal(e)) throw;
891                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
892                         Close();
893                     }
894                 }
895                 catch{
896                 }
897                 throw e;
898             }
899         }
900
901         public override int Read(byte[] buffer, int offset, int size) {
902
903             if (buffer==null) {
904                 throw new ArgumentNullException("buffer");
905             }
906             if (offset<0 || offset>buffer.Length) {
907                 throw new ArgumentOutOfRangeException("offset");
908             }
909             if (size<0 || size>buffer.Length-offset) {
910                 throw new ArgumentOutOfRangeException("size");
911             }
912
913             try{
914                 return base.Read(buffer, offset, size);
915             }
916             catch(Exception e){
917                 try{
918                     if (NclUtilities.IsFatal(e)) throw;
919                     if(e is System.IO.InvalidDataException || e is InvalidOperationException || e is IndexOutOfRangeException){
920                         Close();
921                     }
922                 }
923                 catch{
924                 }
925                 throw e;
926             }
927         }
928
929         void IRequestLifetimeTracker.TrackRequestLifetime(long requestStartTimestamp)
930         {
931             IRequestLifetimeTracker stream = BaseStream as IRequestLifetimeTracker;
932             Debug.Assert(stream != null, "Wrapped stream must implement IRequestLifetimeTracker interface");
933             stream.TrackRequestLifetime(requestStartTimestamp);
934         }
935     }
936
937
938
939 } // namespace System.Net