Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Web / HttpResponse.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="HttpResponse.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 /*
8  * Response intrinsic
9  */
10 namespace System.Web {
11
12     using System.Text;
13     using System.Threading;
14     using System.Threading.Tasks;
15     using System.Runtime.Serialization;
16     using System.IO;
17     using System.Collections;
18     using System.Collections.Specialized;
19     using System.Globalization;
20     using System.Web.Util;
21     using System.Web.Hosting;
22     using System.Web.Caching;
23     using System.Web.Configuration;
24     using System.Web.Routing;
25     using System.Web.UI;
26     using System.Configuration;
27     using System.Security.Permissions;
28     using System.Web.Management;
29     using System.Diagnostics.CodeAnalysis;
30
31
32     /// <devdoc>
33     ///    <para>Used in HttpResponse.WriteSubstitution.</para>
34     /// </devdoc>
35     public delegate String HttpResponseSubstitutionCallback(HttpContext context);
36
37
38     /// <devdoc>
39     ///    <para> Enables type-safe server to browser communication. Used to
40     ///       send Http output to a client.</para>
41     /// </devdoc>
42     public sealed class HttpResponse {
43         private HttpWorkerRequest _wr;              // some response have HttpWorkerRequest
44         private HttpContext _context;               // context
45         private HttpWriter _httpWriter;             // and HttpWriter
46         private TextWriter _writer;                 // others just have Writer
47
48         private HttpHeaderCollection _headers;      // response header collection (IIS7+)
49
50         private bool _headersWritten;
51         private bool _completed;    // after final flush
52         private bool _ended;        // after response.end or execute url
53         private bool _endRequiresObservation; // whether there was a pending call to Response.End that requires observation
54         private bool _flushing;
55         private bool _clientDisconnected;
56         private bool _filteringCompleted;
57         private bool _closeConnectionAfterError;
58
59         // simple properties
60
61         private int         _statusCode = 200;
62         private String      _statusDescription;
63         private bool        _bufferOutput = true;
64         private String      _contentType = "text/html";
65         private String      _charSet;
66         private bool        _customCharSet;
67         private bool        _contentLengthSet;
68         private String      _redirectLocation;
69         private bool        _redirectLocationSet;
70         private Encoding    _encoding;
71         private Encoder     _encoder; // cached encoder for the encoding
72         private Encoding    _headerEncoding; // encoding for response headers, default utf-8
73         private bool        _cacheControlHeaderAdded;
74         private HttpCachePolicy _cachePolicy;
75         private ArrayList   _cacheHeaders;
76         private bool        _suppressHeaders;
77         private bool        _suppressContentSet;
78         private bool        _suppressContent;
79         private string      _appPathModifier;
80         private bool        _isRequestBeingRedirected;
81         private bool        _useAdaptiveError;
82         private bool        _handlerHeadersGenerated;
83         private bool        _sendCacheControlHeader;
84
85         // complex properties
86
87         private ArrayList               _customHeaders;
88         private HttpCookieCollection    _cookies;
89         #pragma warning disable 0649
90         private ResponseDependencyList  _fileDependencyList;
91         private ResponseDependencyList  _virtualPathDependencyList;
92         private ResponseDependencyList  _cacheItemDependencyList;
93         #pragma warning restore 0649
94         private CacheDependency[]       _userAddedDependencies;
95         private CacheDependency         _cacheDependencyForResponse;
96         
97         private ErrorFormatter          _overrideErrorFormatter;
98
99         // cache properties
100         int         _expiresInMinutes;
101         bool        _expiresInMinutesSet;
102         DateTime    _expiresAbsolute;
103         bool        _expiresAbsoluteSet;
104         string      _cacheControl;
105
106         private bool        _statusSet;
107         private int         _subStatusCode;
108         private bool        _versionHeaderSent;
109
110         // These flags for content-type are only used in integrated mode.
111         // DevDivBugs 146983: Content-Type should not be sent when the resonse buffers are empty
112         // DevDivBugs 195148: need to send Content-Type when the handler is managed and the response buffers are non-empty 
113         // Dev10 750934: need to send Content-Type when explicitly set by managed caller
114         private bool        _contentTypeSetByManagedCaller;
115         private bool        _contentTypeSetByManagedHandler;
116
117         // chunking
118         bool        _transferEncodingSet;
119         bool        _chunked;
120
121         // OnSendingHeaders pseudo-event
122         private SubscriptionQueue<Action<HttpContext>> _onSendingHeadersSubscriptionQueue = new SubscriptionQueue<Action<HttpContext>>();
123
124         // mobile redirect properties
125         internal static readonly String RedirectQueryStringVariable = "__redir";
126         internal static readonly String RedirectQueryStringValue = "1";
127         internal static readonly String RedirectQueryStringAssignment = RedirectQueryStringVariable + "=" + RedirectQueryStringValue;
128
129         private static readonly String _redirectQueryString = "?" + RedirectQueryStringAssignment;
130         private static readonly String _redirectQueryStringInline = RedirectQueryStringAssignment + "&";
131
132         internal static event EventHandler Redirecting;
133
134         internal HttpContext Context {
135             get { return _context; }
136             set { _context = value; }
137         }
138
139         internal HttpRequest Request {
140             get {
141                 if (_context == null)
142                     return null;
143                 return _context.Request;
144             }
145         }
146
147         /*
148          * Internal package visible constructor to create responses that
149          * have HttpWorkerRequest
150          *
151          * @param wr Worker Request
152          */
153         internal HttpResponse(HttpWorkerRequest wr, HttpContext context) {
154             _wr = wr;
155             _context = context;
156             // HttpWriter is created in InitResponseWriter
157         }
158
159         // Public constructor for responses that go to an arbitrary writer
160         // Initializes a new instance of the <see langword='HttpResponse'/> class.</para>
161         public HttpResponse(TextWriter writer) {
162             _wr = null;
163             _httpWriter = null;
164             _writer = writer;
165         }
166
167         private bool UsingHttpWriter {
168             get {
169                 return (_httpWriter != null && _writer == _httpWriter);
170             }
171         }
172
173         internal void SetAllocatorProvider(IAllocatorProvider allocator) {
174             if (_httpWriter != null) {
175                 _httpWriter.AllocatorProvider = allocator;
176             }
177         }
178
179         /*
180          *  Cleanup code
181          */
182         internal void Dispose() {
183             // recycle buffers
184             if (_httpWriter != null)
185                 _httpWriter.RecycleBuffers();
186             // recycle dependencies
187             if (_cacheDependencyForResponse != null) {
188                 _cacheDependencyForResponse.Dispose();
189                 _cacheDependencyForResponse = null;
190             }
191             if (_userAddedDependencies != null) {
192                 foreach (CacheDependency dep in _userAddedDependencies) {
193                     dep.Dispose();
194                 }
195                 _userAddedDependencies = null;
196             }
197         }
198
199         internal void InitResponseWriter() {
200             if (_httpWriter == null) {
201                 _httpWriter = new HttpWriter(this);
202
203                 _writer = _httpWriter;
204             }
205         }
206
207         //
208         // Private helper methods
209         //
210
211         private void AppendHeader(HttpResponseHeader h) {
212             if (_customHeaders == null)
213                 _customHeaders = new ArrayList();
214             _customHeaders.Add(h);
215             if (_cachePolicy != null && StringUtil.EqualsIgnoreCase("Set-Cookie", h.Name)) {
216                 _cachePolicy.SetHasSetCookieHeader();
217             }
218         }
219
220         public bool HeadersWritten {
221             get { return _headersWritten; }
222             internal set { _headersWritten = value; }
223         }
224
225         internal ArrayList GenerateResponseHeadersIntegrated(bool forCache) {
226             ArrayList headers = new ArrayList();
227             HttpHeaderCollection responseHeaders = Headers as HttpHeaderCollection;
228             int headerId = 0;
229
230             // copy all current response headers
231             foreach(String key in responseHeaders)
232             {
233                 // skip certain headers that the cache does not cache
234                 // this is based on the cache headers saved separately in AppendHeader
235                 // and not generated in GenerateResponseHeaders in ISAPI mode
236                 headerId = HttpWorkerRequest.GetKnownResponseHeaderIndex(key);
237                 if (headerId >= 0 && forCache &&
238                      (headerId == HttpWorkerRequest.HeaderServer ||
239                       headerId == HttpWorkerRequest.HeaderSetCookie ||
240                       headerId == HttpWorkerRequest.HeaderCacheControl ||
241                       headerId == HttpWorkerRequest.HeaderExpires ||
242                       headerId == HttpWorkerRequest.HeaderLastModified ||
243                       headerId == HttpWorkerRequest.HeaderEtag ||
244                       headerId == HttpWorkerRequest.HeaderVary)) {
245                     continue;
246                 }
247
248                 if ( headerId >= 0 ) {
249                     headers.Add(new HttpResponseHeader(headerId, responseHeaders[key]));
250                 }
251                 else {
252                     headers.Add(new HttpResponseHeader(key, responseHeaders[key]));
253                 }
254             }
255
256             return headers;
257         }
258
259         internal void GenerateResponseHeadersForCookies()
260         {
261             if (_cookies == null || (_cookies.Count == 0 && !_cookies.Changed))
262                 return; // no cookies exist
263
264             HttpHeaderCollection headers = Headers as HttpHeaderCollection;
265             HttpResponseHeader cookieHeader = null;
266             HttpCookie cookie = null;
267             bool needToReset = false;
268
269             // Go through all cookies, and check whether any have been added
270             // or changed.  If a cookie was added, we can simply generate a new
271             // set cookie header for it.  If the cookie collection has been
272             // changed (cleared or cookies removed), or an existing cookie was
273             // changed, we have to regenerate all Set-Cookie headers due to an IIS
274             // limitation that prevents us from being able to delete specific
275             // Set-Cookie headers for items that changed.
276             if (!_cookies.Changed)
277             {
278                 for(int c = 0; c < _cookies.Count; c++)
279                 {
280                     cookie = _cookies[c];
281                     if (cookie.Added) {
282                         if (!cookie.IsInResponseHeader) {
283                             // if a cookie was added, we generate a Set-Cookie header for it
284                             cookieHeader = cookie.GetSetCookieHeader(_context);
285                             headers.SetHeader(cookieHeader.Name, cookieHeader.Value, false);
286                             cookie.IsInResponseHeader = true;
287                         }
288                         cookie.Added = false;
289                         cookie.Changed = false;
290                     }
291                     else if (cookie.Changed) {
292                         // if a cookie has changed, we need to clear all cookie
293                         // headers and re-write them all since we cant delete
294                         // specific existing cookies
295                         needToReset = true;
296                         break;
297                     }
298                 }
299             }
300
301
302             if (_cookies.Changed || needToReset)
303             {
304                 // delete all set cookie headers
305                 headers.Remove("Set-Cookie");
306
307                 // write all the cookies again
308                 for(int c = 0; c < _cookies.Count; c++)
309                 {
310                     // generate a Set-Cookie header for each cookie
311                     cookie = _cookies[c];
312                     cookieHeader = cookie.GetSetCookieHeader(_context);
313                     headers.SetHeader(cookieHeader.Name, cookieHeader.Value, false);
314                     cookie.IsInResponseHeader = true;
315                     cookie.Added = false;
316                     cookie.Changed = false;
317                 }
318
319                 _cookies.Changed = false;
320             }
321         }
322
323         internal void GenerateResponseHeadersForHandler()
324         {
325             if ( !(_wr is IIS7WorkerRequest) ) {
326                 return;
327             }
328
329             String versionHeader = null;
330
331             // Generate the default headers associated with an ASP.NET handler
332             if (!_headersWritten && !_handlerHeadersGenerated) {
333                 try {
334                     // The "sendCacheControlHeader" is default to true, but a false setting in either
335                     // the <httpRuntime> section (legacy) or the <outputCache> section (current) will disable
336                     // sending of that header.
337                     RuntimeConfig config = RuntimeConfig.GetLKGConfig(_context);
338
339                     HttpRuntimeSection runtimeConfig = config.HttpRuntime;
340                     if (runtimeConfig != null) {
341                         versionHeader = runtimeConfig.VersionHeader;
342                         _sendCacheControlHeader = runtimeConfig.SendCacheControlHeader;
343                     }
344
345                     OutputCacheSection outputCacheConfig = config.OutputCache;
346                     if (outputCacheConfig != null) {
347                         _sendCacheControlHeader &= outputCacheConfig.SendCacheControlHeader;
348                     }
349
350                     // DevDiv #406078: Need programmatic way of disabling "Cache-Control: private" response header.
351                     if (SuppressDefaultCacheControlHeader) {
352                         _sendCacheControlHeader = false;
353                     }
354
355                     // Ensure that cacheability is set to cache-control: private
356                     // if it is not explicitly set
357                     if (_sendCacheControlHeader && !_cacheControlHeaderAdded) {
358                         Headers.Set("Cache-Control", "private");
359                     }
360
361                     // set the version header
362                     if (!String.IsNullOrEmpty(versionHeader)) {
363                         Headers.Set("X-AspNet-Version", versionHeader);
364                     }
365
366                     // Force content-type generation
367                     _contentTypeSetByManagedHandler = true;
368                 }
369                 finally {
370                     _handlerHeadersGenerated = true;
371                 }
372             }
373         }
374
375         internal ArrayList GenerateResponseHeaders(bool forCache) {
376             ArrayList   headers = new ArrayList();
377             bool sendCacheControlHeader = HttpRuntimeSection.DefaultSendCacheControlHeader;
378
379             // ASP.NET version header
380             if (!forCache ) {
381
382                 if (!_versionHeaderSent) {
383                     String versionHeader = null;
384
385                     // The "sendCacheControlHeader" is default to true, but a false setting in either
386                     // the <httpRuntime> section (legacy) or the <outputCache> section (current) will disable
387                     // sending of that header.
388                     RuntimeConfig config = RuntimeConfig.GetLKGConfig(_context);
389
390                     HttpRuntimeSection runtimeConfig = config.HttpRuntime;
391                     if (runtimeConfig != null) {
392                         versionHeader = runtimeConfig.VersionHeader;
393                         sendCacheControlHeader = runtimeConfig.SendCacheControlHeader;
394                     }
395
396                     OutputCacheSection outputCacheConfig = config.OutputCache;
397                     if (outputCacheConfig != null) {
398                         sendCacheControlHeader &= outputCacheConfig.SendCacheControlHeader;
399                     }
400
401                     if (!String.IsNullOrEmpty(versionHeader)) {
402                         headers.Add(new HttpResponseHeader("X-AspNet-Version", versionHeader));
403                     }
404
405                     _versionHeaderSent = true;
406                 }
407             }
408
409             // custom headers
410             if (_customHeaders != null) {
411                 int numCustomHeaders = _customHeaders.Count;
412                 for (int i = 0; i < numCustomHeaders; i++)
413                     headers.Add(_customHeaders[i]);
414             }
415
416             // location of redirect
417             if (_redirectLocation != null) {
418                 headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderLocation, _redirectLocation));
419             }
420
421             // don't include headers that the cache changes or omits on a cache hit
422             if (!forCache) {
423                 // cookies
424                 if (_cookies != null) {
425                     int numCookies = _cookies.Count;
426
427                     for (int i = 0; i < numCookies; i++) {
428                         headers.Add(_cookies[i].GetSetCookieHeader(Context));
429                     }
430                 }
431
432                 // cache policy
433                 if (_cachePolicy != null && _cachePolicy.IsModified()) {
434                     _cachePolicy.GetHeaders(headers, this);
435                 }
436                 else {
437                     if (_cacheHeaders != null) {
438                         headers.AddRange(_cacheHeaders);
439                     }
440
441                     /*
442                      * Ensure that cacheability is set to cache-control: private
443                      * if it is not explicitly set.
444                      */
445                     if (!_cacheControlHeaderAdded && sendCacheControlHeader) {
446                         headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderCacheControl, "private"));
447                     }
448                 }
449             }
450
451             //
452             // content type
453             //
454             if ( _statusCode != 204 && _contentType != null) {
455                 String contentType = AppendCharSetToContentType( _contentType );
456                 headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderContentType, contentType));
457             }
458
459             // done
460             return headers;
461         }
462
463         internal string AppendCharSetToContentType(string contentType)
464         {
465             String newContentType = contentType;
466
467             // charset=xxx logic -- append if
468             //      not there already and
469             //          custom set or response encoding used by http writer to convert bytes to chars
470             if (_customCharSet || (_httpWriter != null && _httpWriter.ResponseEncodingUsed)) {
471                 if (contentType.IndexOf("charset=", StringComparison.Ordinal) < 0) {
472                     String charset = Charset;
473                     if (charset.Length > 0) { // not suppressed
474                         newContentType = contentType + "; charset=" + charset;
475                     }
476                 }
477             }
478
479             return newContentType;
480         }
481
482         internal bool UseAdaptiveError {
483             get {
484                 return _useAdaptiveError;
485             }
486             set {
487                 _useAdaptiveError = value;
488             }
489         }
490
491         private void WriteHeaders() {
492             if (_wr == null)
493                 return;
494
495              // Fire pre-send headers event
496
497             if (_context != null && _context.ApplicationInstance != null) {
498                 _context.ApplicationInstance.RaiseOnPreSendRequestHeaders();
499             }
500
501             // status
502             // VSWhidbey 270635: We need to reset the status code for mobile devices.
503             if (UseAdaptiveError) {
504
505                 // VSWhidbey 288054: We should change the status code for cases
506                 // that cannot be handled by mobile devices
507                 // 4xx for Client Error and 5xx for Server Error in HTTP spec
508                 int statusCode = StatusCode;
509                 if (statusCode >= 400 && statusCode < 600) {
510                     this.StatusCode = 200;
511                 }
512             }
513
514             // generate headers before we touch the WorkerRequest since header generation might fail,
515             // and we don't want to have touched the WR if this happens
516             ArrayList headers = GenerateResponseHeaders(false);
517
518             _wr.SendStatus(this.StatusCode, this.StatusDescription);
519
520             // headers encoding
521
522             // unicode messes up the response badly
523             Debug.Assert(!this.HeaderEncoding.Equals(Encoding.Unicode));
524             _wr.SetHeaderEncoding(this.HeaderEncoding);
525
526             // headers
527             HttpResponseHeader header = null;
528             int n = (headers != null) ? headers.Count : 0;
529             for (int i = 0; i < n; i++)
530             {
531                 header = headers[i] as HttpResponseHeader;
532                 header.Send(_wr);
533             }
534         }
535
536         internal int GetBufferedLength() {
537             // if length is greater than Int32.MaxValue, Convert.ToInt32 will throw.
538             // This is okay until we support large response sizes
539             return (_httpWriter != null) ? Convert.ToInt32(_httpWriter.GetBufferedLength()) : 0;
540         }
541
542         private static byte[] s_chunkSuffix = new byte[2] { (byte)'\r', (byte)'\n'};
543         private static byte[] s_chunkEnd    = new byte[5] { (byte)'0',  (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n'};
544
545         private void Flush(bool finalFlush, bool async = false) {
546             // Already completed or inside Flush?
547             if (_completed || _flushing)
548                 return;
549
550             // Special case for non HTTP Writer
551             if (_httpWriter == null) {
552                 _writer.Flush();
553                 return;
554             }
555
556             // Avoid recursive flushes
557             _flushing = true;
558
559             bool needToClearBuffers = false;
560             try {
561
562                 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
563                 if (iis7WorkerRequest != null) {
564                     // generate the handler headers if flushing
565                     GenerateResponseHeadersForHandler();
566
567                     // Push buffers across to native side and explicitly flush.
568                     // IIS7 handles the chunking as necessary so we can omit that logic
569                     UpdateNativeResponse(true /*sendHeaders*/);
570                     
571                     if (!async) {
572                         try {
573                             // force a synchronous send
574                             iis7WorkerRequest.ExplicitFlush();
575                         }
576                         finally {
577                             // always set after flush, successful or not
578                             _headersWritten = true;
579                         }
580                     }
581
582                     return;
583                 }
584
585                 long bufferedLength = 0;
586
587                 //
588                 // Headers
589                 //
590
591                 if (!_headersWritten) {
592                     if (!_suppressHeaders && !_clientDisconnected) {
593                         EnsureSessionStateIfNecessary();
594
595                         if (finalFlush) {
596                             bufferedLength = _httpWriter.GetBufferedLength();
597
598                             // suppress content-type for empty responses
599                             if (!_contentLengthSet && bufferedLength == 0 && _httpWriter != null)
600                                 _contentType = null;
601
602                             SuppressCachingCookiesIfNecessary();
603
604                             // generate response headers
605                             WriteHeaders();
606
607                             // recalculate as sending headers might change it (PreSendHeaders)
608                             bufferedLength = _httpWriter.GetBufferedLength();
609
610                             // Calculate content-length if not set explicitely
611                             // WOS #1380818: Content-Length should not be set for response with 304 status (HTTP.SYS doesn't, and HTTP 1.1 spec implies it)
612                             if (!_contentLengthSet && _statusCode != 304)
613                                 _wr.SendCalculatedContentLength(bufferedLength);
614                         }
615                         else {
616                             // Check if need chunking for HTTP/1.1
617                             if (!_contentLengthSet && !_transferEncodingSet && _statusCode == 200) {
618                                 String protocol = _wr.GetHttpVersion();
619
620                                 if (protocol != null && protocol.Equals("HTTP/1.1")) {
621                                     AppendHeader(new HttpResponseHeader(HttpWorkerRequest.HeaderTransferEncoding, "chunked"));
622                                     _chunked = true;
623                                 }
624
625                                 bufferedLength = _httpWriter.GetBufferedLength();
626                             }
627
628                             WriteHeaders();
629                         }
630                     }
631
632                     _headersWritten = true;
633                 }
634                 else {
635                     bufferedLength = _httpWriter.GetBufferedLength();
636                 }
637
638                 //
639                 // Filter and recalculate length if not done already
640                 //
641
642                 if (!_filteringCompleted) {
643                     _httpWriter.Filter(false);
644                     bufferedLength = _httpWriter.GetBufferedLength();
645                 }
646
647                 //
648                 // Content
649                 //
650
651                 // suppress HEAD content unless overriden
652                 if (!_suppressContentSet && Request != null && Request.HttpVerb == HttpVerb.HEAD)
653                     _suppressContent = true;
654
655                 if (_suppressContent || _ended) {
656                     _httpWriter.ClearBuffers();
657                     bufferedLength = 0;
658                 }
659
660                 if (!_clientDisconnected) {
661                     // Fire pre-send request event
662                     if (_context != null && _context.ApplicationInstance != null)
663                         _context.ApplicationInstance.RaiseOnPreSendRequestContent();
664
665                     if (_chunked) {
666                         if (bufferedLength > 0) {
667                             byte[] chunkPrefix = Encoding.ASCII.GetBytes(Convert.ToString(bufferedLength, 16) + "\r\n");
668                             _wr.SendResponseFromMemory(chunkPrefix, chunkPrefix.Length);
669
670                             _httpWriter.Send(_wr);
671
672                             _wr.SendResponseFromMemory(s_chunkSuffix, s_chunkSuffix.Length);
673                         }
674
675                         if (finalFlush)
676                             _wr.SendResponseFromMemory(s_chunkEnd, s_chunkEnd.Length);
677                     }
678                     else {
679                         _httpWriter.Send(_wr);
680                     }
681                     
682                     if (!async) {
683                         needToClearBuffers = !finalFlush;
684                         _wr.FlushResponse(finalFlush);
685                     }
686                     _wr.UpdateResponseCounters(finalFlush, (int)bufferedLength);
687                 }
688             }
689             finally {
690                 _flushing = false;
691
692                 // Remember if completed
693                 if (finalFlush && _headersWritten)
694                     _completed = true;
695
696                 // clear buffers even if FlushResponse throws
697                 if (needToClearBuffers)
698                     _httpWriter.ClearBuffers();
699             }
700         }
701
702         internal void FinalFlushAtTheEndOfRequestProcessing() {
703             FinalFlushAtTheEndOfRequestProcessing(false);
704         }
705
706         internal void FinalFlushAtTheEndOfRequestProcessing(bool needPipelineCompletion) {
707                 Flush(true);
708         }
709
710         // Returns true if the HttpWorkerRequest supports asynchronous flush; otherwise false.
711         public bool SupportsAsyncFlush {
712             get {
713                 return (_wr != null && _wr.SupportsAsyncFlush);
714             }
715         }
716
717         // Sends the currently buffered response to the client.  If the underlying HttpWorkerRequest
718         // supports asynchronous flush and this method is called from an asynchronous module event
719         // or asynchronous handler, then the send will be performed asynchronously.  Otherwise the
720         // implementation resorts to a synchronous flush.  The HttpResponse.SupportsAsyncFlush property 
721         // returns the value of HttpWorkerRequest.SupportsAsyncFlush.  Asynchronous flush is supported
722         // for IIS 6.0 and higher.
723         public IAsyncResult BeginFlush(AsyncCallback callback, Object state) {
724             if (_completed)
725                 throw new HttpException(SR.GetString(SR.Cannot_flush_completed_response));
726
727             // perform async flush if it is supported
728             if (_wr != null && _wr.SupportsAsyncFlush && !_context.IsInCancellablePeriod) {
729                 Flush(false, true);
730                 return _wr.BeginFlush(callback, state);
731             }
732
733             // perform a sync flush since async is not supported
734             FlushAsyncResult ar = new FlushAsyncResult(callback, state);
735             try {
736                 Flush(false);
737             }
738             catch(Exception e) {
739                 ar.SetError(e);
740             }
741             ar.Complete(0, HResults.S_OK, IntPtr.Zero, synchronous: true);
742             return ar;
743         }
744
745         // Finish an asynchronous flush.
746         public void EndFlush(IAsyncResult asyncResult) {
747             // finish async flush if it is supported
748             if (_wr != null && _wr.SupportsAsyncFlush && !_context.IsInCancellablePeriod) {
749                 // integrated mode doesn't set this until after ExplicitFlush is called,
750                 // but classic mode sets it after WriteHeaders is called
751                 _headersWritten = true;
752                 if (!(_wr is IIS7WorkerRequest)) {
753                     _httpWriter.ClearBuffers();
754                 }
755                 _wr.EndFlush(asyncResult);
756                 return;
757             }
758             
759             // finish sync flush since async is not supported
760             if (asyncResult == null)
761                 throw new ArgumentNullException("asyncResult");
762             FlushAsyncResult ar = asyncResult as FlushAsyncResult;
763             if (ar == null)
764                 throw new ArgumentException(null, "asyncResult");
765             ar.ReleaseWaitHandleWhenSignaled();
766             if (ar.Error != null) {
767                 ar.Error.Throw();
768             }
769         }
770
771         public Task FlushAsync() {
772             return Task.Factory.FromAsync(BeginFlush, EndFlush, state: null);
773         }
774
775         // WOS 1555777: kernel cache support
776         // If the response can be kernel cached, return the kernel cache key;
777         // otherwise return null.  The kernel cache key is used to invalidate
778         // the entry if a dependency changes or the item is flushed from the
779         // managed cache for any reason.
780         internal String SetupKernelCaching(String originalCacheUrl) {
781             // don't kernel cache if we have a cookie header
782             if (_cookies != null && _cookies.Count != 0) {
783                 _cachePolicy.SetHasSetCookieHeader();
784                 return null;
785             }
786
787             bool enableKernelCacheForVaryByStar = IsKernelCacheEnabledForVaryByStar();
788
789             // check cache policy
790             if (!_cachePolicy.IsKernelCacheable(Request, enableKernelCacheForVaryByStar)) {
791                 return null;
792             }
793
794             // check configuration if the kernel mode cache is enabled
795             HttpRuntimeSection runtimeConfig = RuntimeConfig.GetLKGConfig(_context).HttpRuntime;
796             if (runtimeConfig == null || !runtimeConfig.EnableKernelOutputCache) {
797                 return null;
798             }
799
800             double seconds = (_cachePolicy.UtcGetAbsoluteExpiration() - DateTime.UtcNow).TotalSeconds;
801             if (seconds <= 0) {
802                 return null;
803             }
804
805             int secondsToLive = seconds < Int32.MaxValue ? (int) seconds : Int32.MaxValue;
806             string kernelCacheUrl = _wr.SetupKernelCaching(secondsToLive, originalCacheUrl, enableKernelCacheForVaryByStar);
807
808             if (kernelCacheUrl != null) {
809                 // Tell cache policy not to use max-age as kernel mode cache doesn't update it
810                 _cachePolicy.SetNoMaxAgeInCacheControl();
811             }
812
813             return kernelCacheUrl;
814         }
815
816         /*
817          * Disable kernel caching for this response.  If kernel caching is not supported, this method
818          * returns without performing any action.
819          */
820         public void DisableKernelCache() {
821             if (_wr == null) {
822                 return;
823             }
824
825             _wr.DisableKernelCache();
826         }
827
828         /*
829          * Disable IIS user-mode caching for this response.  If IIS user-mode caching is not supported, this method
830          * returns without performing any action.
831          */
832         public void DisableUserCache() {
833             if (_wr == null) {
834                 return;
835             }
836
837             _wr.DisableUserCache();
838         }
839
840         private bool IsKernelCacheEnabledForVaryByStar()
841         {
842             OutputCacheSection outputCacheConfig = RuntimeConfig.GetAppConfig().OutputCache;
843             return (_cachePolicy.IsVaryByStar && outputCacheConfig.EnableKernelCacheForVaryByStar);
844         }
845
846         internal void FilterOutput() {
847             if(_filteringCompleted) {
848                 return;
849             }
850
851             try {
852                 if (UsingHttpWriter) {
853                     IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
854                     if (iis7WorkerRequest != null) {
855                         _httpWriter.FilterIntegrated(true, iis7WorkerRequest);
856                     }
857                     else {
858                         _httpWriter.Filter(true);
859                     }
860                 }
861             }
862             finally {
863                 _filteringCompleted = true;
864             }
865         }
866
867         /// <devdoc>
868         /// Prevents any other writes to the Response
869         /// </devdoc>
870         internal void IgnoreFurtherWrites() {
871             if (UsingHttpWriter) {
872                 _httpWriter.IgnoreFurtherWrites();
873             }
874         }
875
876         /*
877          * Is the entire response buffered so far
878          */
879         internal bool IsBuffered() {
880             return !_headersWritten && UsingHttpWriter;
881         }
882
883         //  Expose cookie collection to request
884         //    Gets the HttpCookie collection sent by the current request.</para>
885         public HttpCookieCollection Cookies {
886             get {
887                 if (_cookies == null)
888                     _cookies = new HttpCookieCollection(this, false);
889
890                 return _cookies;
891             }
892         }
893
894         // returns TRUE iff there is at least one response cookie marked Shareable = false
895         internal bool ContainsNonShareableCookies() {
896             if (_cookies != null) {
897                 for (int i = 0; i < _cookies.Count; i++) {
898                     if (!_cookies[i].Shareable) {
899                         return true;
900                     }
901                 }
902             }
903             return false;
904         }
905
906         internal HttpCookieCollection GetCookiesNoCreate() {
907             return _cookies;
908         }
909
910         public NameValueCollection Headers {
911             get {
912                 if ( !(_wr is IIS7WorkerRequest) ) {
913                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
914                 }
915
916                 if (_headers == null) {
917                     _headers = new HttpHeaderCollection(_wr, this, 16);
918                 }
919
920                 return _headers;
921             }
922         }
923
924         /*
925          * Add dependency on a file to the current response
926          */
927
928         /// <devdoc>
929         ///    <para>Adds dependency on a file to the current response.</para>
930         /// </devdoc>
931         public void AddFileDependency(String filename) {
932             _fileDependencyList.AddDependency(filename, "filename");
933         }
934
935         // Add dependency on a list of files to the current response
936
937         //   Adds dependency on a group of files to the current response.
938         public void AddFileDependencies(ArrayList filenames) {
939             _fileDependencyList.AddDependencies(filenames, "filenames");
940         }
941
942
943         public void AddFileDependencies(string[] filenames) {
944             _fileDependencyList.AddDependencies(filenames, "filenames");
945         }
946
947         internal void AddVirtualPathDependencies(string[] virtualPaths) {
948             _virtualPathDependencyList.AddDependencies(virtualPaths, "virtualPaths", false, Request.Path);
949         }
950
951         internal void AddFileDependencies(string[] filenames, DateTime utcTime) {
952             _fileDependencyList.AddDependencies(filenames, "filenames", false, utcTime);
953         }
954
955         // Add dependency on another cache item to the response.
956         public void AddCacheItemDependency(string cacheKey) {
957             _cacheItemDependencyList.AddDependency(cacheKey, "cacheKey");
958         }
959
960         // Add dependency on a list of cache items to the response.
961         public void AddCacheItemDependencies(ArrayList cacheKeys) {
962             _cacheItemDependencyList.AddDependencies(cacheKeys, "cacheKeys");
963         }
964
965
966         public void AddCacheItemDependencies(string[] cacheKeys) {
967             _cacheItemDependencyList.AddDependencies(cacheKeys, "cacheKeys");
968         }
969
970         // Add dependency on one or more CacheDependency objects to the response
971         public void AddCacheDependency(params CacheDependency[] dependencies) {
972             if (dependencies == null) {
973                 throw new ArgumentNullException("dependencies");
974             }
975             if (dependencies.Length == 0) {
976                 return;
977             }
978             if (_cacheDependencyForResponse != null) {
979                 throw new InvalidOperationException(SR.GetString(SR.Invalid_operation_cache_dependency));
980             }
981             if (_userAddedDependencies == null) {
982                 // copy array argument contents so they can't be changed beneath us
983                 _userAddedDependencies = (CacheDependency[]) dependencies.Clone();
984             }
985             else {
986                 CacheDependency[] deps = new CacheDependency[_userAddedDependencies.Length + dependencies.Length];
987                 int i = 0;
988                 for (i = 0; i < _userAddedDependencies.Length; i++) {
989                     deps[i] = _userAddedDependencies[i];
990                 }
991                 for (int j = 0; j < dependencies.Length; j++) {
992                     deps[i + j] = dependencies[j];
993                 }
994                 _userAddedDependencies = deps;
995             }
996             Cache.SetDependencies(true);
997         }
998
999         public static void RemoveOutputCacheItem(string path) {
1000             RemoveOutputCacheItem(path, null);
1001         }
1002
1003         public static void RemoveOutputCacheItem(string path, string providerName) {
1004             if (path == null)
1005                 throw new ArgumentNullException("path");
1006             if (StringUtil.StringStartsWith(path, "\\\\") || path.IndexOf(':') >= 0 || !UrlPath.IsRooted(path))
1007                 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_remove, path));
1008
1009             string key = OutputCacheModule.CreateOutputCachedItemKey(
1010                     path, HttpVerb.GET, null, null);
1011
1012             if (providerName == null) {
1013                 OutputCache.Remove(key, (HttpContext)null);
1014             }
1015             else {
1016                 OutputCache.RemoveFromProvider(key, providerName);
1017             }
1018
1019             key = OutputCacheModule.CreateOutputCachedItemKey(
1020                     path, HttpVerb.POST, null, null);
1021             
1022             if (providerName == null) {
1023                 OutputCache.Remove(key, (HttpContext)null);
1024             }
1025             else { 
1026                 OutputCache.RemoveFromProvider(key, providerName);
1027             }
1028         }
1029
1030         // Check if there are file dependencies.
1031         internal bool HasFileDependencies() {
1032             return _fileDependencyList.HasDependencies();
1033         }
1034
1035         // Check if there are item dependencies.
1036         internal bool HasCacheItemDependencies() {
1037             return _cacheItemDependencyList.HasDependencies();
1038         }
1039
1040         internal CacheDependency CreateCacheDependencyForResponse() {
1041             if (_cacheDependencyForResponse == null) {
1042                 CacheDependency dependency;
1043                 
1044                 // N.B. - add file dependencies last so that we hit the file changes monitor
1045                 // just once.
1046                 dependency = _cacheItemDependencyList.CreateCacheDependency(CacheDependencyType.CacheItems, null);
1047                 dependency = _fileDependencyList.CreateCacheDependency(CacheDependencyType.Files, dependency);
1048                 dependency = _virtualPathDependencyList.CreateCacheDependency(CacheDependencyType.VirtualPaths, dependency);
1049                 
1050                 // N.B. we add in the aggregate dependency here, and return it,
1051                 // so this function should only be called once, because the resulting
1052                 // dependency can only be added to the cache once
1053                 if (_userAddedDependencies != null) {
1054                     AggregateCacheDependency agg = new AggregateCacheDependency();
1055                     agg.Add(_userAddedDependencies);
1056                     if (dependency != null) {
1057                         agg.Add(dependency);
1058                     }
1059                     // clear it because we added them to the dependencies for the response
1060                     _userAddedDependencies = null;
1061                     _cacheDependencyForResponse = agg;
1062                 }
1063                 else {
1064                     _cacheDependencyForResponse = dependency;
1065                 }
1066             }
1067             return _cacheDependencyForResponse;
1068         }
1069
1070         // Get response headers and content as HttpRawResponse
1071         internal HttpRawResponse GetSnapshot() {
1072             int statusCode = 200;
1073             string statusDescription = null;
1074             ArrayList headers = null;
1075             ArrayList buffers = null;
1076             bool hasSubstBlocks = false;
1077
1078             if (!IsBuffered())
1079                 throw new HttpException(SR.GetString(SR.Cannot_get_snapshot_if_not_buffered));
1080
1081             IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
1082
1083             // data
1084             if (!_suppressContent) {
1085                 if (iis7WorkerRequest != null) {
1086                     buffers = _httpWriter.GetIntegratedSnapshot(out hasSubstBlocks, iis7WorkerRequest);
1087                 }
1088                 else {
1089                     buffers = _httpWriter.GetSnapshot(out hasSubstBlocks);
1090                 }
1091             }
1092
1093             // headers (after data as the data has side effects (like charset, see ASURT 113202))
1094             if (!_suppressHeaders) {
1095                 statusCode = _statusCode;
1096                 statusDescription = _statusDescription;
1097                 // In integrated pipeline, we need to use the current response headers
1098                 // from the response (these may have been generated by other handlers, etc)
1099                 // instead of the ASP.NET cached headers
1100                 if (iis7WorkerRequest != null) {
1101                     headers = GenerateResponseHeadersIntegrated(true);
1102                 }
1103                 else {
1104                     headers = GenerateResponseHeaders(true);
1105                 }
1106             }
1107             return new HttpRawResponse(statusCode, statusDescription, headers, buffers, hasSubstBlocks);
1108         }
1109
1110         // Send saved response snapshot as the entire response
1111         internal void UseSnapshot(HttpRawResponse rawResponse, bool sendBody) {
1112             if (_headersWritten)
1113                 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_after_headers_sent));
1114
1115             if (_httpWriter == null)
1116                 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter));
1117
1118             ClearAll();
1119
1120             // restore status
1121             StatusCode = rawResponse.StatusCode;
1122             StatusDescription = rawResponse.StatusDescription;
1123
1124             // restore headers
1125             ArrayList headers = rawResponse.Headers;
1126             int n = (headers != null) ? headers.Count : 0;
1127             for (int i = 0; i < n; i++) {
1128                 HttpResponseHeader h = (HttpResponseHeader)(headers[i]);
1129                 this.AppendHeader(h.Name, h.Value);
1130             }
1131
1132             // restore content
1133             SetResponseBuffers(rawResponse.Buffers);
1134   
1135             _suppressContent = !sendBody;         
1136         }
1137
1138         // set the response content bufffers
1139         internal void SetResponseBuffers(ArrayList buffers) {
1140             if (_httpWriter == null) {
1141                 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter));
1142             }
1143
1144             _httpWriter.UseSnapshot(buffers);
1145         }
1146
1147         internal void CloseConnectionAfterError() {
1148             _closeConnectionAfterError = true;
1149         }
1150
1151         private void WriteErrorMessage(Exception e, bool dontShowSensitiveErrors) {
1152             ErrorFormatter errorFormatter = null;
1153             CultureInfo uiculture = null, savedUiculture = null;
1154             bool needToRestoreUiculture = false;
1155
1156             if (_context.DynamicUICulture != null) {
1157                 // if the user set the culture dynamically use it
1158                 uiculture =  _context.DynamicUICulture;
1159             }
1160             else  {
1161                 // get the UI culture under which the error text must be created (use LKG to avoid errors while reporting error)
1162                 GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1163                 if ((globConfig != null) && (!String.IsNullOrEmpty(globConfig.UICulture))) {
1164                     try {
1165                         uiculture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
1166                     }
1167                     catch {
1168                     }
1169                 }
1170             }
1171
1172             //  In Integrated mode, generate the necessary response headers for the error
1173             GenerateResponseHeadersForHandler();
1174
1175             // set the UI culture
1176             if (uiculture != null) {
1177                 savedUiculture = Thread.CurrentThread.CurrentUICulture;
1178                 Thread.CurrentThread.CurrentUICulture = uiculture;
1179                 needToRestoreUiculture = true;
1180             }
1181
1182             try {
1183                 try {
1184                     // Try to get an error formatter
1185                     errorFormatter = GetErrorFormatter(e);
1186 #if DBG
1187                     Debug.Trace("internal", "Error stack for " + Request.Path, e);
1188 #endif
1189                     if (dontShowSensitiveErrors && !errorFormatter.CanBeShownToAllUsers)
1190                         errorFormatter = new GenericApplicationErrorFormatter(Request.IsLocal);
1191
1192                     Debug.Trace("internal", "errorFormatter's type = " +  errorFormatter.GetType());
1193
1194                     if (ErrorFormatter.RequiresAdaptiveErrorReporting(Context)) {
1195                         _writer.Write(errorFormatter.GetAdaptiveErrorMessage(Context, dontShowSensitiveErrors));
1196                     }
1197                     else {
1198                         _writer.Write(errorFormatter.GetHtmlErrorMessage(dontShowSensitiveErrors));
1199
1200                         // Write a stack dump in an HTML comment for debugging purposes
1201                         // Only show it for Asp permission medium or higher (ASURT 126373)
1202                         if (!dontShowSensitiveErrors &&
1203                             HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) {
1204                             _writer.Write("<!-- \r\n");
1205                             WriteExceptionStack(e);
1206                             _writer.Write("-->");
1207                         }
1208                          if (!dontShowSensitiveErrors && !Request.IsLocal ) {
1209                              _writer.Write("<!-- \r\n");
1210                              _writer.Write(SR.GetString(SR.Information_Disclosure_Warning));
1211                              _writer.Write("-->");
1212                          }
1213                     }
1214
1215                     if (_closeConnectionAfterError) {
1216                         Flush();
1217                         Close();
1218                     }
1219                 }
1220                 finally {
1221                     // restore ui culture
1222                     if (needToRestoreUiculture)
1223                         Thread.CurrentThread.CurrentUICulture = savedUiculture;
1224                 }
1225             }
1226             catch { // Protect against exception filters
1227                 throw;
1228             }
1229         }
1230
1231         internal void SetOverrideErrorFormatter(ErrorFormatter errorFormatter) {
1232             _overrideErrorFormatter = errorFormatter;
1233         }
1234
1235         internal ErrorFormatter GetErrorFormatter(Exception e) {
1236             ErrorFormatter  errorFormatter = null;
1237
1238             if (_overrideErrorFormatter != null) {
1239                 return _overrideErrorFormatter;
1240             }
1241
1242             // Try to get an error formatter
1243             errorFormatter = HttpException.GetErrorFormatter(e);
1244
1245             if (errorFormatter == null) {
1246                 ConfigurationException ce = e as ConfigurationException;
1247                 if (ce != null && !String.IsNullOrEmpty(ce.Filename))
1248                     errorFormatter = new ConfigErrorFormatter(ce);
1249             }
1250
1251             // If we couldn't get one, create one here
1252             if (errorFormatter == null) {
1253                 // If it's a 404, use a special error page, otherwise, use a more
1254                 // generic one.
1255                 if (_statusCode == 404)
1256                     errorFormatter = new PageNotFoundErrorFormatter(Request.Path);
1257                 else if (_statusCode == 403)
1258                     errorFormatter = new PageForbiddenErrorFormatter(Request.Path);
1259                 else {
1260                     if (e is System.Security.SecurityException)
1261                         errorFormatter = new SecurityErrorFormatter(e);
1262                     else
1263                         errorFormatter = new UnhandledErrorFormatter(e);
1264                 }
1265             }
1266
1267             // Show config source only on local request for security reasons
1268             // Config file snippet may unintentionally reveal sensitive information (not related to the error)
1269             ConfigErrorFormatter configErrorFormatter = errorFormatter as ConfigErrorFormatter;
1270             if (configErrorFormatter != null) {
1271                 configErrorFormatter.AllowSourceCode = Request.IsLocal;
1272             }
1273
1274             return errorFormatter;
1275         }
1276
1277         private void WriteOneExceptionStack(Exception e) {
1278             Exception subExcep = e.InnerException;
1279             if (subExcep != null)
1280                 WriteOneExceptionStack(subExcep);
1281
1282             string title = "[" + e.GetType().Name + "]";
1283             if (e.Message != null && e.Message.Length > 0)
1284                 title += ": " + HttpUtility.HtmlEncode(e.Message);
1285
1286             _writer.WriteLine(title);
1287             if (e.StackTrace != null)
1288                 _writer.WriteLine(e.StackTrace);
1289         }
1290
1291         private void WriteExceptionStack(Exception e) {
1292             ConfigurationErrorsException errors = e as ConfigurationErrorsException;
1293             if (errors == null) {
1294                 WriteOneExceptionStack(e);
1295             }
1296             else {
1297                 // Write the original exception to get the first error with
1298                 // a full stack trace
1299                 WriteOneExceptionStack(e);
1300
1301                 // Write additional errors, which will contain truncated stacks
1302                 ICollection col = errors.Errors;
1303                 if (col.Count > 1) {
1304                     bool firstSkipped = false;
1305                     foreach (ConfigurationException ce in col) {
1306                         if (!firstSkipped) {
1307                             firstSkipped = true;
1308                             continue;
1309                         }
1310
1311                         _writer.WriteLine("---");
1312                         WriteOneExceptionStack(ce);
1313                     }
1314                 }
1315             }
1316         }
1317
1318         internal void ReportRuntimeError(Exception e, bool canThrow, bool localExecute) {
1319             CustomErrorsSection customErrorsSetting = null;
1320             bool useCustomErrors = false;
1321             int code = -1;
1322
1323             if (_completed)
1324                 return;
1325
1326             // always try to disable IIS custom errors when we send an error
1327             if (_wr != null) {
1328                 _wr.TrySkipIisCustomErrors = true;
1329             }
1330
1331             if (!localExecute) {
1332                 code = HttpException.GetHttpCodeForException(e);
1333
1334                 // Don't raise event for 404.  See VSWhidbey 124147.
1335                 if (code != 404) {
1336                     WebBaseEvent.RaiseRuntimeError(e, this);
1337                 }
1338
1339                 // This cannot use the HttpContext.IsCustomErrorEnabled property, since it must call
1340                 // GetSettings() with the canThrow parameter.
1341                 customErrorsSetting = CustomErrorsSection.GetSettings(_context, canThrow);
1342                 if (customErrorsSetting != null)
1343                     useCustomErrors = customErrorsSetting.CustomErrorsEnabled(Request);
1344                 else
1345                     useCustomErrors = true;
1346             }
1347
1348             if (!_headersWritten) {
1349                 // nothing sent yet - entire response
1350
1351                 if (code == -1) {
1352                     code = HttpException.GetHttpCodeForException(e);
1353                 }
1354
1355                 // change 401 to 500 in case the config is not to impersonate
1356                 if (code == 401 && !_context.IsClientImpersonationConfigured)
1357                     code = 500;
1358
1359                 if (_context.TraceIsEnabled)
1360                     _context.Trace.StatusCode = code;
1361
1362                 if (!localExecute && useCustomErrors) {
1363                     String redirect = (customErrorsSetting != null) ? customErrorsSetting.GetRedirectString(code) : null;
1364
1365                     RedirectToErrorPageStatus redirectStatus = RedirectToErrorPage(redirect, customErrorsSetting.RedirectMode);
1366                     switch (redirectStatus) {
1367                         case RedirectToErrorPageStatus.Success:
1368                             // success - nothing to do
1369                             break;
1370
1371                         case RedirectToErrorPageStatus.NotAttempted:
1372                             // if no redirect display generic error
1373                             ClearAll();
1374                             StatusCode = code;
1375                             WriteErrorMessage(e, dontShowSensitiveErrors: true);
1376                             break;
1377
1378                         default:
1379                             // DevDiv #70492 - If we tried to display the custom error page but failed in doing so, we should display
1380                             // a generic error message instead of trying to display the original error. We have a compat switch on
1381                             // the <customErrors> element to control this behavior.
1382
1383                             if (customErrorsSetting.AllowNestedErrors) {
1384                                 // The user has set the compat switch to use the original (pre-bug fix) behavior.
1385                                 goto case RedirectToErrorPageStatus.NotAttempted;
1386                             }
1387
1388                             ClearAll();
1389                             StatusCode = 500;
1390                             HttpException dummyException = new HttpException();
1391                             dummyException.SetFormatter(new CustomErrorFailedErrorFormatter());
1392                             WriteErrorMessage(dummyException, dontShowSensitiveErrors: true);
1393                             break;
1394                     }
1395                 }
1396                 else {
1397                     ClearAll();
1398                     StatusCode = code;
1399                     WriteErrorMessage(e, dontShowSensitiveErrors: false);
1400                 }
1401             }
1402             else {
1403                 Clear();
1404
1405                 if (_contentType != null && _contentType.Equals("text/html")) {
1406                     // in the middle of Html - break Html
1407                     Write("\r\n\r\n</pre></table></table></table></table></table>");
1408                     Write("</font></font></font></font></font>");
1409                     Write("</i></i></i></i></i></b></b></b></b></b></u></u></u></u></u>");
1410                     Write("<p>&nbsp;</p><hr>\r\n\r\n");
1411                 }
1412
1413                 WriteErrorMessage(e, useCustomErrors);
1414             }
1415         }
1416
1417         internal void SynchronizeStatus(int statusCode, int subStatusCode, string description) {
1418             _statusCode = statusCode;
1419             _subStatusCode = subStatusCode;
1420             _statusDescription = description;
1421         }
1422
1423
1424         internal void SynchronizeHeader(int knownHeaderIndex, string name, string value) {
1425             HttpHeaderCollection headers = Headers as HttpHeaderCollection;
1426             headers.SynchronizeHeader(name, value);
1427
1428             // unknown headers have an index < 0
1429             if (knownHeaderIndex < 0) {
1430                 return;
1431             }
1432
1433             bool fHeadersWritten = HeadersWritten;
1434             HeadersWritten = false; // Turn off the warning for "Headers have been written and can not be set"
1435             try {
1436                 switch (knownHeaderIndex) {
1437                 case HttpWorkerRequest.HeaderCacheControl:
1438                     _cacheControlHeaderAdded = true;
1439                     break;
1440                 case HttpWorkerRequest.HeaderContentType:
1441                     _contentType = value;
1442                     break;
1443                 case HttpWorkerRequest.HeaderLocation:
1444                     _redirectLocation = value;
1445                     _redirectLocationSet = false;
1446                     break;
1447                 case HttpWorkerRequest.HeaderSetCookie:
1448                     // If the header is Set-Cookie, update the corresponding
1449                     // cookie in the cookies collection
1450                     if (value != null) {
1451                         HttpCookie cookie = HttpRequest.CreateCookieFromString(value);
1452                         // do not write this cookie back to IIS
1453                         cookie.IsInResponseHeader = true;
1454                         Cookies.Set(cookie);
1455                         cookie.Changed = false;
1456                         cookie.Added = false;
1457                     }
1458                     break;
1459                 }
1460             } finally {
1461                 HeadersWritten = fHeadersWritten;
1462             }
1463         }
1464
1465         internal void SyncStatusIntegrated() {
1466             Debug.Assert(_wr is IIS7WorkerRequest, "_wr is IIS7WorkerRequest");
1467              if (!_headersWritten && _statusSet) {
1468                  // For integrated pipeline, synchronize the status immediately so that the FREB log
1469                  // correctly indicates the module and notification that changed the status.
1470                  _wr.SendStatus(_statusCode, _subStatusCode, this.StatusDescription);
1471                  _statusSet = false;
1472              }
1473         }
1474
1475         // Public properties
1476
1477         // Http status code
1478         //    Gets or sets the HTTP status code of output returned to client.
1479         public int StatusCode {
1480             get {
1481                 return _statusCode;
1482             }
1483
1484             set {
1485                 if (_headersWritten)
1486                     throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1487
1488                 if (_statusCode != value) {
1489                     _statusCode = value;
1490                     _subStatusCode = 0;
1491                     _statusDescription = null;
1492                     _statusSet = true;
1493                 }
1494             }
1495         }
1496
1497         // the IIS sub status code
1498         // since this doesn't get emitted in the protocol
1499         // we won't send it through the worker request interface
1500         // directly
1501         public int SubStatusCode {
1502             get {
1503                 if ( !(_wr is IIS7WorkerRequest) ) {
1504                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1505                 }
1506
1507                 return _subStatusCode;
1508             }
1509             set {
1510                 if ( !(_wr is IIS7WorkerRequest) ) {
1511                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1512                 }
1513
1514                 if (_headersWritten) {
1515                     throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1516                 }
1517
1518                 _subStatusCode = value;
1519                 _statusSet = true;
1520             }
1521         }
1522
1523         // Allows setting both the status and the substatus individually. If not in IIS7 integrated mode,
1524         // the substatus code is ignored so as not to throw an exception.
1525         internal void SetStatusCode(int statusCode, int subStatus = -1) {
1526             StatusCode = statusCode;
1527             if (subStatus >= 0 && _wr is IIS7WorkerRequest) {
1528                 SubStatusCode = subStatus;
1529             }
1530         }
1531
1532         /*
1533          * Http status description string
1534          */
1535
1536         // Http status description string
1537         //    Gets or sets the HTTP status string of output returned to the client.
1538         public String StatusDescription {
1539             get {
1540                 if (_statusDescription == null)
1541                     _statusDescription = HttpWorkerRequest.GetStatusDescription(_statusCode);
1542
1543                 return _statusDescription;
1544             }
1545
1546             set {
1547                 if (_headersWritten)
1548                     throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1549
1550                 if (value != null && value.Length > 512)  // ASURT 124743
1551                     throw new ArgumentOutOfRangeException("value");
1552                 _statusDescription = value;
1553                 _statusSet = true;
1554             }
1555         }
1556
1557         public bool TrySkipIisCustomErrors {
1558             get {
1559                 if (_wr != null) {
1560                     return _wr.TrySkipIisCustomErrors;
1561                 }
1562                 return false;
1563             }
1564             set {
1565                 if (_wr != null) {
1566                     _wr.TrySkipIisCustomErrors = value;
1567                 }
1568             }
1569         }
1570
1571         /// <summary>
1572         /// By default, the FormsAuthenticationModule hooks EndRequest and converts HTTP 401 status codes to
1573         /// HTTP 302, redirecting to the login page. This isn't appropriate for certain classes of errors,
1574         /// e.g. where authentication succeeded but authorization failed, or where the current request is
1575         /// an AJAX or web service request. This property provides a way to suppress the redirect behavior
1576         /// and send the original status code to the client.
1577         /// </summary>
1578         public bool SuppressFormsAuthenticationRedirect {
1579             get;
1580             set;
1581         }
1582
1583         /// <summary>
1584         /// By default, ASP.NET sends a "Cache-Control: private" response header unless an explicit cache
1585         /// policy has been specified for this response. This property allows suppressing this default
1586         /// response header on a per-request basis. It can still be suppressed for the entire application
1587         /// by setting the appropriate value in &lt;httpRuntime&gt; or &lt;outputCache&gt;. See
1588         /// http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.sendcachecontrolheader.aspx
1589         /// for more information on those config elements.
1590         /// </summary>
1591         /// <remarks>
1592         /// Developers should use caution when suppressing the default Cache-Control header, as proxies
1593         /// and other intermediaries may treat responses without this header as cacheable by default.
1594         /// This could lead to the inadvertent caching of sensitive information.
1595         /// See RFC 2616, Sec. 13.4, for more information.
1596         /// </remarks>
1597         public bool SuppressDefaultCacheControlHeader {
1598             get;
1599             set;
1600         }
1601
1602         // Flag indicating to buffer the output
1603         //    Gets or sets a value indicating whether HTTP output is buffered.
1604         public bool BufferOutput {
1605             get {
1606                 return _bufferOutput;
1607             }
1608
1609             set {
1610                 if (_bufferOutput != value) {
1611                     _bufferOutput = value;
1612
1613                     if (_httpWriter != null)
1614                         _httpWriter.UpdateResponseBuffering();
1615                 }
1616             }
1617         }
1618
1619         // Gets the Content-Encoding HTTP response header.
1620         internal String GetHttpHeaderContentEncoding() {
1621             string coding = null;
1622             if (_wr is IIS7WorkerRequest) {
1623                 if (_headers != null) {
1624                     coding = _headers["Content-Encoding"];
1625                 }
1626             }
1627             else if (_customHeaders != null) {
1628                 int numCustomHeaders = _customHeaders.Count;
1629                 for (int i = 0; i < numCustomHeaders; i++) {
1630                     HttpResponseHeader h = (HttpResponseHeader)_customHeaders[i];
1631                     if (h.Name == "Content-Encoding") {
1632                         coding = h.Value;
1633                         break;
1634                     }
1635                 }
1636             }
1637             return coding;
1638         }
1639
1640         /*
1641          * Content-type
1642          */
1643
1644         /// <devdoc>
1645         ///    <para>Gets or sets the
1646         ///       HTTP MIME type of output.</para>
1647         /// </devdoc>
1648         public String ContentType {
1649             get {
1650                 return _contentType;
1651             }
1652
1653             set {
1654                 if (_headersWritten) {
1655                     // Don't throw if the new content type is the same as the current one
1656                     if (_contentType == value)
1657                         return;
1658
1659                     throw new HttpException(SR.GetString(SR.Cannot_set_content_type_after_headers_sent));
1660                 }
1661
1662                 _contentTypeSetByManagedCaller = true;
1663                 _contentType = value;
1664             }
1665         }
1666
1667
1668         //    Gets or sets the HTTP charset of output.
1669         public String Charset {
1670             get {
1671                 if (_charSet == null)
1672                     _charSet = ContentEncoding.WebName;
1673
1674                 return _charSet;
1675             }
1676
1677             set {
1678                 if (_headersWritten)
1679                     throw new HttpException(SR.GetString(SR.Cannot_set_content_type_after_headers_sent));
1680
1681                 if (value != null)
1682                     _charSet = value;
1683                 else
1684                     _charSet = String.Empty;  // to differentiate between not set (default) and empty chatset
1685
1686                 _customCharSet = true;
1687             }
1688         }
1689
1690         // Content encoding for conversion
1691         //   Gets or sets the HTTP character set of output.
1692         public Encoding ContentEncoding {
1693             get {
1694                 if (_encoding == null) {
1695                     // use LKG config because Response.ContentEncoding is need to display [config] error
1696                     GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1697                     if (globConfig != null)
1698                         _encoding = globConfig.ResponseEncoding;
1699
1700                     if (_encoding == null)
1701                         _encoding = Encoding.Default;
1702                 }
1703
1704                 return _encoding;
1705             }
1706
1707             set {
1708                 if (value == null)
1709                     throw new ArgumentNullException("value");
1710
1711                 if (_encoding == null || !_encoding.Equals(value)) {
1712                     _encoding = value;
1713                     _encoder = null;   // flush cached encoder
1714
1715                     if (_httpWriter != null)
1716                         _httpWriter.UpdateResponseEncoding();
1717                 }
1718             }
1719         }
1720
1721
1722         public Encoding HeaderEncoding {
1723             get {
1724                 if (_headerEncoding == null) {
1725                     // use LKG config because Response.ContentEncoding is need to display [config] error
1726                     GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1727                     if (globConfig != null)
1728                         _headerEncoding = globConfig.ResponseHeaderEncoding;
1729
1730                     // default to UTF-8 (also for Unicode as headers cannot be double byte encoded)
1731                     if (_headerEncoding == null || _headerEncoding.Equals(Encoding.Unicode))
1732                         _headerEncoding = Encoding.UTF8;
1733                 }
1734
1735                 return _headerEncoding;
1736             }
1737
1738             set {
1739                 if (value == null)
1740                     throw new ArgumentNullException("value");
1741
1742                 if (value.Equals(Encoding.Unicode)) {
1743                     throw new HttpException(SR.GetString(SR.Invalid_header_encoding, value.WebName));
1744                 }
1745
1746                 if (_headerEncoding == null || !_headerEncoding.Equals(value)) {
1747                     if (_headersWritten)
1748                         throw new HttpException(SR.GetString(SR.Cannot_set_header_encoding_after_headers_sent));
1749
1750                     _headerEncoding = value;
1751                 }
1752             }
1753         }
1754
1755         // Encoder cached for the current encoding
1756         internal Encoder ContentEncoder {
1757             get {
1758                 if (_encoder == null) {
1759                     Encoding e = ContentEncoding;
1760                     _encoder = e.GetEncoder();
1761
1762                     // enable best fit mapping accoding to config
1763                     // (doesn't apply to utf-8 which is the default, thus optimization)
1764
1765                     if (!e.Equals(Encoding.UTF8)) {
1766                         bool enableBestFit = false;
1767
1768                         GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1769                         if (globConfig != null) {
1770                             enableBestFit = globConfig.EnableBestFitResponseEncoding;
1771                         }
1772
1773                         if (!enableBestFit) {
1774                             // setting 'fallback' disables best fit mapping
1775                             _encoder.Fallback = new EncoderReplacementFallback();
1776                         }
1777                     }
1778                 }
1779                 return _encoder;
1780             }
1781         }
1782
1783         // Cache policy
1784         //    Returns the caching semantics of the Web page (expiration time, privacy, vary clauses).
1785         public HttpCachePolicy Cache {
1786             get {
1787                 if (_cachePolicy == null) {
1788                     _cachePolicy = new HttpCachePolicy();
1789                 }
1790
1791                 return _cachePolicy;
1792             }
1793         }
1794
1795         // Return whether or not we have cache policy. We don't want to create it in
1796         // situations where we don't modify it.
1797         internal bool HasCachePolicy {
1798             get {
1799                 return _cachePolicy != null;
1800             }
1801         }
1802
1803         // Client connected flag
1804         //   Gets a value indicating whether the client is still connected to the server.
1805         public bool IsClientConnected {
1806             get {
1807                 if (_clientDisconnected)
1808                     return false;
1809
1810                 if (_wr != null && !_wr.IsClientConnected()) {
1811                     _clientDisconnected = true;
1812                     return false;
1813                 }
1814
1815                 return true;
1816             }
1817         }
1818
1819         /// <summary>
1820         /// Returns a CancellationToken that is tripped when the client disconnects. This can be used
1821         /// to listen for async disconnect notifications.
1822         /// </summary>
1823         /// <remarks>
1824         /// This method requires that the application be hosted on IIS 7.5 or higher and that the
1825         /// application pool be running the integrated mode pipeline.
1826         /// 
1827         /// Consumers should be aware of some restrictions when consuming this CancellationToken.
1828         /// Failure to heed these warnings can lead to race conditions, deadlocks, or other
1829         /// undefined behavior.
1830         /// 
1831         /// - This API is thread-safe. However, ASP.NET will dispose of the token object at the
1832         ///   end of the request. Consumers should exercise caution and ensure that they're not
1833         ///   calling into this API outside the bounds of a single request. This is similar to
1834         ///   the contract with BCL Task-returning methods which take a CancellationToken as a
1835         ///   parameter: the callee should not touch the CancellationToken after the returned
1836         ///   Task transitions to a terminal state.
1837         /// 
1838         /// - DO NOT wait on the CancellationToken.WaitHandle, as this defeats the purpose of an
1839         ///   async notification and can cause deadlocks.
1840         /// 
1841         /// - DO NOT call the CancellationToken.Register overloads which invoke the callback on
1842         ///   the original SynchronizationContext.
1843         /// 
1844         /// - DO NOT consume HttpContext or other non-thread-safe ASP.NET intrinsic objects from
1845         ///   within the callback provided to Register. Remember: the callback may be running
1846         ///   concurrently with other ASP.NET or application code.
1847         /// 
1848         /// - DO keep the callback methods short-running and non-blocking. Make every effort to
1849         ///   avoid throwing exceptions from within the callback methods.
1850         /// 
1851         /// - We do not guarantee that we will ever transition the token to a canceled state.
1852         ///   For example, if the request finishes without the client having disconnected, we
1853         ///   will dispose of this token as mentioned earlier without having first canceled it.
1854         /// </remarks>
1855         public CancellationToken ClientDisconnectedToken {
1856             get {
1857                 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest;
1858                 CancellationToken cancellationToken;
1859                 if (wr != null && wr.TryGetClientDisconnectedCancellationToken(out cancellationToken)) {
1860                     return cancellationToken;
1861                 }
1862                 else {
1863                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_75_Integrated));
1864                 }
1865             }
1866         }
1867
1868         public bool IsRequestBeingRedirected {
1869             get {
1870                 return _isRequestBeingRedirected;
1871             }
1872             internal set {
1873                 _isRequestBeingRedirected = value;
1874             }
1875         }
1876
1877
1878         /// <devdoc>
1879         ///    <para>Gets or Sets a redirection string (value of location resposne header) for redirect response.</para>
1880         /// </devdoc>
1881         public String RedirectLocation {
1882             get { return _redirectLocation; }
1883             set {
1884                 if (_headersWritten)
1885                     throw new HttpException(SR.GetString(SR.Cannot_append_header_after_headers_sent));
1886
1887                 _redirectLocation = value;
1888                 _redirectLocationSet = true;
1889             }
1890         }
1891
1892         /*
1893          * Disconnect client
1894          */
1895
1896         /// <devdoc>
1897         ///    <para>Closes the socket connection to a client.</para>
1898         /// </devdoc>
1899         public void Close() {
1900             if (!_clientDisconnected && !_completed && _wr != null) {
1901                 _wr.CloseConnection();
1902                 _clientDisconnected = true;
1903             }
1904         }
1905
1906         // TextWriter object
1907         //    Enables custom output to the outgoing Http content body.
1908         public TextWriter Output {
1909             get { return _writer;}
1910             set { _writer = value; }
1911         }
1912
1913         internal TextWriter SwitchWriter(TextWriter writer) {
1914             TextWriter oldWriter = _writer;
1915             _writer = writer;
1916             return oldWriter;
1917         }
1918
1919         // Output stream
1920         //       Enables binary output to the outgoing Http content body.
1921         public Stream OutputStream {
1922             get {
1923                 if (!UsingHttpWriter)
1924                     throw new HttpException(SR.GetString(SR.OutputStream_NotAvail));
1925
1926                 return _httpWriter.OutputStream;
1927             }
1928         }
1929
1930         // ASP classic compat
1931         //    Writes a string of binary characters to the HTTP output stream.
1932         public void BinaryWrite(byte[] buffer) {
1933             OutputStream.Write(buffer, 0, buffer.Length);
1934         }
1935
1936
1937         //  Appends a PICS (Platform for Internet Content Selection) label HTTP header to the output stream.
1938         public void Pics(String value) {
1939             AppendHeader("PICS-Label", value);
1940         }
1941
1942         // Filtering stream
1943         //       Specifies a wrapping filter object to modify HTTP entity body before transmission.
1944         public Stream Filter {
1945             get {
1946                 if (UsingHttpWriter)
1947                     return _httpWriter.GetCurrentFilter();
1948                 else
1949                     return null;
1950             }
1951
1952             set {
1953                 if (UsingHttpWriter) {
1954                     _httpWriter.InstallFilter(value);
1955
1956                     IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
1957                     if (iis7WorkerRequest != null) {
1958                         iis7WorkerRequest.ResponseFilterInstalled();
1959                     }
1960                 }
1961                 else
1962                     throw new HttpException(SR.GetString(SR.Filtering_not_allowed));
1963             }
1964
1965         }
1966
1967         // Flag to suppress writing of content
1968         //    Gets or sets a value indicating that HTTP content will not be sent to client.
1969         public bool SuppressContent {
1970             get {
1971                 return _suppressContent;
1972             }
1973
1974             set {
1975                 _suppressContent = value;
1976                 _suppressContentSet = true;
1977             }
1978         }
1979
1980         //
1981         // Public methods
1982         //
1983
1984         /*
1985           * Add Http custom header
1986           *
1987           * @param name header name
1988           * @param value header value
1989           */
1990
1991         /// <devdoc>
1992         ///    <para>Adds an HTTP
1993         ///       header to the output stream.</para>
1994         /// </devdoc>
1995         public void AppendHeader(String name, String value) {
1996             bool isCacheHeader = false;
1997
1998             if (_headersWritten)
1999                 throw new HttpException(SR.GetString(SR.Cannot_append_header_after_headers_sent));
2000
2001             // some headers are stored separately or require special action
2002             int knownHeaderIndex = HttpWorkerRequest.GetKnownResponseHeaderIndex(name);
2003
2004             switch (knownHeaderIndex) {
2005                 case HttpWorkerRequest.HeaderContentType:
2006                     ContentType = value;
2007                     return; // don't keep as custom header
2008
2009                 case HttpWorkerRequest.HeaderContentLength:
2010                     _contentLengthSet = true;
2011                     break;
2012
2013                 case HttpWorkerRequest.HeaderLocation:
2014                     RedirectLocation = value;
2015                     return; // don't keep as custom header
2016
2017                 case HttpWorkerRequest.HeaderTransferEncoding:
2018                     _transferEncodingSet = true;
2019                     break;
2020
2021                 case HttpWorkerRequest.HeaderCacheControl:
2022                     _cacheControlHeaderAdded = true;
2023                     goto case HttpWorkerRequest.HeaderExpires;
2024                 case HttpWorkerRequest.HeaderExpires:
2025                 case HttpWorkerRequest.HeaderLastModified:
2026                 case HttpWorkerRequest.HeaderEtag:
2027                 case HttpWorkerRequest.HeaderVary:
2028                     isCacheHeader = true;
2029                     break;
2030             }
2031
2032             // In integrated mode, write the headers directly
2033             if (_wr is IIS7WorkerRequest) {
2034                 Headers.Add(name, value);
2035             }
2036             else {
2037                 if (isCacheHeader)
2038                 {
2039                     // don't keep as custom header
2040                     if (_cacheHeaders == null) {
2041                         _cacheHeaders = new ArrayList();
2042                     }
2043
2044                     _cacheHeaders.Add(new HttpResponseHeader(knownHeaderIndex, value));
2045                     return;
2046                 }
2047                 else {
2048                     HttpResponseHeader h;
2049                     if (knownHeaderIndex >= 0)
2050                         h = new HttpResponseHeader(knownHeaderIndex, value);
2051                     else
2052                         h = new HttpResponseHeader(name, value);
2053
2054                     AppendHeader(h);
2055                 }
2056             }
2057         }
2058
2059
2060         /// <internalonly/>
2061         /// <devdoc>
2062         ///    <para>
2063         ///       Adds an HTTP
2064         ///       cookie to the output stream.
2065         ///    </para>
2066         /// </devdoc>
2067         public void AppendCookie(HttpCookie cookie) {
2068             if (_headersWritten)
2069                 throw new HttpException(SR.GetString(SR.Cannot_append_cookie_after_headers_sent));
2070
2071             Cookies.AddCookie(cookie, true);
2072             OnCookieAdd(cookie);
2073         }
2074
2075
2076         /// <internalonly/>
2077         /// <devdoc>
2078         /// </devdoc>
2079         public void SetCookie(HttpCookie cookie) {
2080             if (_headersWritten)
2081                 throw new HttpException(SR.GetString(SR.Cannot_append_cookie_after_headers_sent));
2082
2083             Cookies.AddCookie(cookie, false);
2084             OnCookieCollectionChange();
2085         }
2086
2087         internal void BeforeCookieCollectionChange() {
2088             if (_headersWritten)
2089                 throw new HttpException(SR.GetString(SR.Cannot_modify_cookies_after_headers_sent));
2090         }
2091
2092         internal void OnCookieAdd(HttpCookie cookie) {
2093             // add to request's cookies as well
2094             Request.AddResponseCookie(cookie);
2095         }
2096
2097         internal void OnCookieCollectionChange() {
2098             // synchronize with request cookie collection
2099             Request.ResetCookies();
2100         }
2101
2102         // Clear response headers
2103         //    Clears all headers from the buffer stream.
2104         public void ClearHeaders() {
2105             if (_headersWritten)
2106                 throw new HttpException(SR.GetString(SR.Cannot_clear_headers_after_headers_sent));
2107
2108             StatusCode = 200;
2109             _subStatusCode = 0;
2110             _statusDescription = null;
2111
2112             _contentType = "text/html";
2113             _contentTypeSetByManagedCaller = false;
2114             _charSet = null;
2115             _customCharSet = false;
2116             _contentLengthSet = false;
2117
2118             _redirectLocation = null;
2119             _redirectLocationSet = false;
2120             _isRequestBeingRedirected = false;
2121
2122             _customHeaders = null;
2123
2124             if (_headers != null) {
2125                 _headers.ClearInternal();
2126             }
2127
2128             _transferEncodingSet = false;
2129             _chunked = false;
2130
2131             if (_cookies != null) {
2132                 _cookies.Reset();
2133                 Request.ResetCookies();
2134             }
2135
2136             if (_cachePolicy != null) {
2137                 _cachePolicy.Reset();
2138             }
2139
2140             _cacheControlHeaderAdded = false;
2141             _cacheHeaders = null;
2142
2143             _suppressHeaders = false;
2144             _suppressContent = false;
2145             _suppressContentSet = false;
2146
2147             _expiresInMinutes = 0;
2148             _expiresInMinutesSet = false;
2149             _expiresAbsolute = DateTime.MinValue;
2150             _expiresAbsoluteSet = false;
2151             _cacheControl = null;
2152
2153             IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
2154             if (iis7WorkerRequest != null) {
2155                 // clear the native response as well
2156                 ClearNativeResponse(false, true, iis7WorkerRequest);
2157                 // DevDiv 162749:
2158                 // We need to regenerate Cache-Control: private only when the handler is managed and
2159                 // configuration has <outputCache sendCacheControlHeader="true" /> in system.web
2160                 // caching section.
2161                 if (_handlerHeadersGenerated && _sendCacheControlHeader) {
2162                     Headers.Set("Cache-Control", "private");
2163                 }
2164                 _handlerHeadersGenerated = false;
2165             }
2166         }
2167
2168
2169         /// <devdoc>
2170         ///    <para>Clears all content output from the buffer stream.</para>
2171         /// </devdoc>
2172         public void ClearContent() {
2173             Clear();
2174         }
2175
2176         /*
2177          * Clear response buffer and headers. (For ASP compat doesn't clear headers)
2178          */
2179
2180         /// <devdoc>
2181         ///    <para>Clears all headers and content output from the buffer stream.</para>
2182         /// </devdoc>
2183         public void Clear() {
2184             if (UsingHttpWriter)
2185                 _httpWriter.ClearBuffers();
2186
2187             IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
2188             if (iis7WorkerRequest != null) {
2189                 // clear the native response buffers too
2190                 ClearNativeResponse(true, false, iis7WorkerRequest);
2191             }
2192
2193
2194         }
2195
2196         /*
2197          * Clear response buffer and headers. Internal. Used to be 'Clear'.
2198          */
2199         internal void ClearAll() {
2200             if (!_headersWritten)
2201                 ClearHeaders();
2202             Clear();
2203         }
2204
2205         /*
2206          * Flush response currently buffered
2207          */
2208
2209         /// <devdoc>
2210         ///    <para>Sends all currently buffered output to the client.</para>
2211         /// </devdoc>
2212         public void Flush() {
2213             if (_completed)
2214                 throw new HttpException(SR.GetString(SR.Cannot_flush_completed_response));
2215
2216             Flush(false);
2217         }
2218
2219         // Registers a callback that the ASP.NET runtime will invoke immediately before
2220         // response headers are sent for this request. This differs from the IHttpModule-
2221         // level pipeline event in that this is a per-request subscription rather than
2222         // a per-application subscription. The intent is that the callback may modify
2223         // the response status code or may set a response cookie or header. Other usage
2224         // notes and caveats:
2225         //
2226         // - This API is available only in the IIS integrated mode pipeline and only
2227         //   if response headers haven't yet been sent for this request.
2228         // - The ASP.NET runtime does not guarantee anything about the thread that the
2229         //   callback is invoked on. For example, the callback may be invoked synchronously
2230         //   on a background thread if a background flush is being performed.
2231         //   HttpContext.Current is not guaranteed to be available on such a thread.
2232         // - The callback must not call any API that manipulates the response entity body
2233         //   or that results in a flush. For example, the callback must not call
2234         //   Response.Redirect, as that method may manipulate the response entity body.
2235         // - The callback must contain only short-running synchronous code. Trying to kick
2236         //   off an asynchronous operation or wait on such an operation could result in
2237         //   a deadlock.
2238         // - The callback must not throw, otherwise behavior is undefined.
2239         [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = @"The normal event pattern doesn't work between HttpResponse and HttpResponseBase since the signatures differ.")]
2240         public ISubscriptionToken AddOnSendingHeaders(Action<HttpContext> callback) {
2241             if (callback == null) {
2242                 throw new ArgumentNullException("callback");
2243             }
2244
2245             if (!(_wr is IIS7WorkerRequest)) {
2246                 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
2247             }
2248
2249             if (HeadersWritten) {
2250                 throw new HttpException(SR.GetString(SR.Cannot_call_method_after_headers_sent_generic));
2251             }
2252
2253             return _onSendingHeadersSubscriptionQueue.Enqueue(callback);
2254         }
2255
2256         /*
2257          * Append string to the log record
2258          *
2259          * @param param string to append to the log record
2260          */
2261
2262         /// <devdoc>
2263         ///    <para>Adds custom log information to the IIS log file.</para>
2264         /// </devdoc>
2265         [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
2266         public void AppendToLog(String param) {
2267             // only makes sense for IIS
2268             if (_wr is System.Web.Hosting.ISAPIWorkerRequest)
2269                 ((System.Web.Hosting.ISAPIWorkerRequest)_wr).AppendLogParameter(param);
2270             else if (_wr is System.Web.Hosting.IIS7WorkerRequest)
2271                 _context.Request.AppendToLogQueryString(param);
2272         }
2273
2274
2275         /// <devdoc>
2276         ///    <para>Redirects a client to a new URL.</para>
2277         /// </devdoc>
2278         public void Redirect(String url) {
2279             Redirect(url, true, false);
2280         }
2281
2282         /// <devdoc>
2283         ///    <para>Redirects a client to a new URL.</para>
2284         /// </devdoc>
2285         public void Redirect(String url, bool endResponse) {
2286             Redirect(url, endResponse, false);
2287         }
2288
2289         public void RedirectToRoute(object routeValues) {
2290             RedirectToRoute(new RouteValueDictionary(routeValues));
2291         }
2292
2293         public void RedirectToRoute(string routeName) {
2294             RedirectToRoute(routeName, (RouteValueDictionary)null, false);
2295         }
2296
2297         public void RedirectToRoute(RouteValueDictionary routeValues) {
2298             RedirectToRoute(null /* routeName */, routeValues, false);
2299         }
2300
2301         public void RedirectToRoute(string routeName, object routeValues) {
2302             RedirectToRoute(routeName, new RouteValueDictionary(routeValues), false);
2303         }
2304
2305         public void RedirectToRoute(string routeName, RouteValueDictionary routeValues) {
2306             RedirectToRoute(routeName, routeValues, false);
2307         }
2308
2309         private void RedirectToRoute(string routeName, RouteValueDictionary routeValues, bool permanent) {
2310             string destinationUrl = null;
2311             VirtualPathData data = RouteTable.Routes.GetVirtualPath(Request.RequestContext, routeName, routeValues);
2312             if (data != null) {
2313                 destinationUrl = data.VirtualPath;
2314             }
2315
2316             if (String.IsNullOrEmpty(destinationUrl)) {
2317                 throw new InvalidOperationException(SR.GetString(SR.No_Route_Found_For_Redirect));
2318             }
2319
2320             Redirect(destinationUrl, false /* endResponse */, permanent);
2321         }
2322
2323         public void RedirectToRoutePermanent(object routeValues) {
2324             RedirectToRoutePermanent(new RouteValueDictionary(routeValues));
2325         }
2326
2327         public void RedirectToRoutePermanent(string routeName) {
2328             RedirectToRoute(routeName, (RouteValueDictionary)null, true);
2329         }
2330
2331         public void RedirectToRoutePermanent(RouteValueDictionary routeValues) {
2332             RedirectToRoute(null /* routeName */, routeValues, true);
2333         }
2334
2335         public void RedirectToRoutePermanent(string routeName, object routeValues) {
2336             RedirectToRoute(routeName, new RouteValueDictionary(routeValues), true);
2337         }
2338
2339         public void RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues) {
2340             RedirectToRoute(routeName, routeValues, true);
2341         }
2342
2343
2344         /// <devdoc>
2345         ///    <para>Redirects a client to a new URL with a 301.</para>
2346         /// </devdoc>
2347         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
2348             Justification="Warning was suppressed for consistency with existing similar Redirect API")]
2349         public void RedirectPermanent(String url) {
2350             Redirect(url, true, true);
2351         }
2352
2353         /// <devdoc>
2354         ///    <para>Redirects a client to a new URL with a 301.</para>
2355         /// </devdoc>
2356         [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
2357             Justification = "Warning was suppressed for consistency with existing similar Redirect API")]
2358         public void RedirectPermanent(String url, bool endResponse) {
2359             Redirect(url, endResponse, true);
2360         }
2361
2362         internal void Redirect(String url, bool endResponse, bool permanent) {
2363 #if DBG
2364             string originalUrl = url;
2365 #endif
2366             if (url == null)
2367                 throw new ArgumentNullException("url");
2368
2369             if (url.IndexOf('\n') >= 0)
2370                 throw new ArgumentException(SR.GetString(SR.Cannot_redirect_to_newline));
2371
2372             if (_headersWritten)
2373                 throw new HttpException(SR.GetString(SR.Cannot_redirect_after_headers_sent));
2374
2375             Page page = _context.Handler as Page;
2376             if ((page != null) && page.IsCallback) {
2377                 throw new ApplicationException(SR.GetString(SR.Redirect_not_allowed_in_callback));
2378             }
2379
2380             url = ApplyRedirectQueryStringIfRequired(url);
2381
2382             url = ApplyAppPathModifier(url);
2383
2384             url = ConvertToFullyQualifiedRedirectUrlIfRequired(url);
2385
2386             url = UrlEncodeRedirect(url);
2387
2388             Clear();
2389
2390             // If it's a Page and SmartNavigation is on, return a short script
2391             // to perform the redirect instead of returning a 302 (bugs ASURT 82331/86782)
2392 #pragma warning disable 0618    // To avoid SmartNavigation deprecation warning
2393             if (page != null && page.IsPostBack && page.SmartNavigation && (Request["__smartNavPostBack"] == "true")) {
2394 #pragma warning restore 0618
2395                 Write("<BODY><ASP_SMARTNAV_RDIR url=\"");
2396                 Write(HttpUtility.HtmlEncode(url));
2397                 Write("\"></ASP_SMARTNAV_RDIR>");
2398
2399                 Write("</BODY>");
2400             }
2401             else {
2402                 this.StatusCode = permanent ? 301 : 302;
2403                 RedirectLocation = url;
2404                 // DevDivBugs 158137: 302 Redirect vulnerable to XSS
2405                 // A ---- of protocol identifiers. We don't want to UrlEncode
2406                 // URLs matching these schemes in order to not break the
2407                 // physical Object Moved to link.
2408                 if (UriUtil.IsSafeScheme(url)) {
2409                     url = HttpUtility.HtmlAttributeEncode(url);
2410                 }
2411                 else {
2412                     url = HttpUtility.HtmlAttributeEncode(HttpUtility.UrlEncode(url));
2413                 }
2414                 Write("<html><head><title>Object moved</title></head><body>\r\n");
2415                 Write("<h2>Object moved to <a href=\"" + url + "\">here</a>.</h2>\r\n");
2416                 Write("</body></html>\r\n");
2417             }
2418
2419             _isRequestBeingRedirected = true;
2420
2421 #if DBG
2422             Debug.Trace("ClientUrl", "*** Redirect (" + originalUrl + ") --> " + RedirectLocation + " ***");
2423 #endif
2424
2425             var redirectingHandler = Redirecting;
2426             if (redirectingHandler != null) {
2427                 redirectingHandler(this, EventArgs.Empty);
2428             }
2429
2430             if (endResponse)
2431                 End();
2432         }
2433
2434         internal string ApplyRedirectQueryStringIfRequired(string url) {
2435             if (Request == null || (string)Request.Browser["requiresPostRedirectionHandling"] != "true")
2436                 return url;
2437
2438             Page page = _context.Handler as Page;
2439             if (page != null && !page.IsPostBack)
2440                 return url;
2441
2442             //do not add __redir=1 if it already exists
2443             int i = url.IndexOf(RedirectQueryStringAssignment, StringComparison.Ordinal);
2444             if(i == -1) {
2445                 i = url.IndexOf('?');
2446                 if (i >= 0) {
2447                     url = url.Insert(i + 1, _redirectQueryStringInline);
2448                 }
2449                 else {
2450                     url = String.Concat(url, _redirectQueryString);
2451                 }
2452             }
2453             return url;
2454         }
2455
2456         //
2457         // Redirect to error page appending ?aspxerrorpath if no query string in the url.
2458         // Fails to redirect if request is already for error page.
2459         // Suppresses all errors.
2460         // See comments on RedirectToErrorPageStatus type for meaning of return values.
2461         //
2462         internal RedirectToErrorPageStatus RedirectToErrorPage(String url, CustomErrorsRedirectMode redirectMode) {
2463             const String qsErrorMark = "aspxerrorpath";
2464
2465             try {
2466                 if (String.IsNullOrEmpty(url))
2467                     return RedirectToErrorPageStatus.NotAttempted;   // nowhere to redirect
2468
2469                 if (_headersWritten)
2470                     return RedirectToErrorPageStatus.NotAttempted;
2471
2472                 if (Request.QueryString[qsErrorMark] != null)
2473                     return RedirectToErrorPageStatus.Failed;   // already in error redirect
2474
2475                 if (redirectMode == CustomErrorsRedirectMode.ResponseRewrite) {
2476                     Context.Server.Execute(url);
2477                 }
2478                 else {
2479                     // append query string
2480                     if (url.IndexOf('?') < 0)
2481                         url = url + "?" + qsErrorMark + "=" + HttpEncoderUtility.UrlEncodeSpaces(Request.Path);
2482
2483                     // redirect without response.end
2484                     Redirect(url, false /*endResponse*/);
2485                 }
2486             }
2487             catch {
2488                 return RedirectToErrorPageStatus.Failed;
2489             }
2490
2491             return RedirectToErrorPageStatus.Success;
2492         }
2493
2494         // Represents the result of calling RedirectToErrorPage
2495         internal enum RedirectToErrorPageStatus {
2496             NotAttempted, // Redirect or rewrite was not attempted, possibly because no redirect URL was specified
2497             Success, // Redirect or rewrite was attempted and succeeded
2498             Failed // Redirect or rewrite was attempted and failed, possibly due to the error page throwing
2499         }
2500
2501         // Implementation of the DefaultHttpHandler for IIS6+
2502         internal bool CanExecuteUrlForEntireResponse {
2503             get {
2504                 // if anything is sent, too late
2505                 if (_headersWritten) {
2506                     return false;
2507                 }
2508
2509                 // must have the right kind of worker request
2510                 if (_wr == null || !_wr.SupportsExecuteUrl) {
2511                     return false;
2512                 }
2513
2514                 // must not be capturing output to custom writer
2515                 if (!UsingHttpWriter) {
2516                     return false;
2517                 }
2518
2519                 // there is some cached output not yet sent
2520                 if (_httpWriter.GetBufferedLength() != 0) {
2521                     return false;
2522                 }
2523
2524                 // can't use execute url with filter installed
2525                 if (_httpWriter.FilterInstalled) {
2526                     return false;
2527                 }
2528
2529                 if (_cachePolicy != null && _cachePolicy.IsModified()) {
2530                     return false;
2531                 }
2532
2533                 return true;
2534             }
2535         }
2536
2537         [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
2538         internal IAsyncResult BeginExecuteUrlForEntireResponse(
2539                                     String pathOverride, NameValueCollection requestHeaders,
2540                                     AsyncCallback cb, Object state) {
2541             Debug.Assert(CanExecuteUrlForEntireResponse);
2542
2543             // prepare user information
2544             String userName, userAuthType;
2545             if (_context != null && _context.User != null) {
2546                 userName     = _context.User.Identity.Name;
2547                 userAuthType = _context.User.Identity.AuthenticationType;
2548             }
2549             else {
2550                 userName = String.Empty;
2551                 userAuthType = String.Empty;
2552             }
2553
2554             // get the path
2555             String path = Request.RewrittenUrl; // null is ok
2556
2557             if (pathOverride != null) {
2558                 path = pathOverride;
2559             }
2560
2561             // get the headers
2562             String headers = null;
2563
2564             if (requestHeaders != null) {
2565                 int numHeaders = requestHeaders.Count;
2566
2567                 if (numHeaders > 0) {
2568                     StringBuilder sb = new StringBuilder();
2569
2570                     for (int i = 0; i < numHeaders; i++) {
2571                         sb.Append(requestHeaders.GetKey(i));
2572                         sb.Append(": ");
2573                         sb.Append(requestHeaders.Get(i));
2574                         sb.Append("\r\n");
2575                     }
2576
2577                     headers = sb.ToString();
2578                 }
2579             }
2580
2581             byte[] entity = null;
2582             if (_context != null && _context.Request != null) {
2583                 entity = _context.Request.EntityBody;
2584             }
2585
2586             Debug.Trace("ExecuteUrl", "HttpResponse.BeginExecuteUrlForEntireResponse:" +
2587                 " path=" + path + " headers=" + headers +
2588                 " userName=" + userName + " authType=" + userAuthType);
2589
2590             // call worker request to start async execute url for this request
2591             IAsyncResult ar = _wr.BeginExecuteUrl(
2592                     path,
2593                     null, // this method
2594                     headers,
2595                     true, // let execute url send headers
2596                     true, // add user info
2597                     _wr.GetUserToken(),
2598                     userName,
2599                     userAuthType,
2600                     entity,
2601                     cb,
2602                     state);
2603
2604             // suppress further sends from ASP.NET
2605             // (only if succeeded starting async operation - not is 'finally' block)
2606             _headersWritten = true;
2607             _ended = true;
2608
2609             return ar;
2610         }
2611
2612         internal void EndExecuteUrlForEntireResponse(IAsyncResult result) {
2613             Debug.Trace("ExecuteUrl", "HttpResponse.EndExecuteUrlForEntireResponse");
2614             _wr.EndExecuteUrl(result);
2615         }
2616
2617         // Methods to write from file
2618
2619         //    Writes values to an HTTP output content stream.
2620         public void Write(String s) {
2621             _writer.Write(s);
2622         }
2623
2624         // Writes values to an HTTP output content stream.
2625         public void Write(Object obj) {
2626             _writer.Write(obj);
2627         }
2628
2629
2630         /// <devdoc>
2631         ///    <para>Writes values to an HTTP output content stream.</para>
2632         /// </devdoc>
2633         public void Write(char ch) {
2634             _writer.Write(ch);
2635         }
2636
2637
2638         /// <devdoc>
2639         ///    <para>Writes values to an HTTP output content stream.</para>
2640         /// </devdoc>
2641         public void Write(char[] buffer, int index, int count) {
2642             _writer.Write(buffer, index, count);
2643         }
2644
2645
2646         /// <devdoc>
2647         ///    <para>Writes a substition block to the response.</para>
2648         /// </devdoc>
2649         public void WriteSubstitution(HttpResponseSubstitutionCallback callback) {
2650             // cannot be instance method on a control
2651             if (callback.Target != null && callback.Target is Control) {
2652                 throw new ArgumentException(SR.GetString(SR.Invalid_substitution_callback), "callback");
2653             }
2654
2655             if (UsingHttpWriter) {
2656                 // HttpWriter can take substitution blocks
2657                 _httpWriter.WriteSubstBlock(callback, _wr as IIS7WorkerRequest);
2658             }
2659             else {
2660                 // text writer -- write as string
2661                 _writer.Write(callback(_context));
2662             }
2663
2664             // set the cache policy: reduce cachability from public to server
2665             if (_cachePolicy != null && _cachePolicy.GetCacheability() == HttpCacheability.Public)
2666                 _cachePolicy.SetCacheability(HttpCacheability.Server);
2667         }
2668
2669         /*
2670          * Helper method to write from file stream
2671          *
2672          * Handles only TextWriter case. For real requests
2673          * HttpWorkerRequest can take files
2674          */
2675         private void WriteStreamAsText(Stream f, long offset, long size) {
2676             if (size < 0)
2677                 size = f.Length - offset;
2678
2679             if (size > 0) {
2680                 if (offset > 0)
2681                     f.Seek(offset, SeekOrigin.Begin);
2682
2683                 byte[] fileBytes = new byte[(int)size];
2684                 int bytesRead = f.Read(fileBytes, 0, (int)size);
2685                 _writer.Write(Encoding.Default.GetChars(fileBytes, 0, bytesRead));
2686             }
2687         }
2688
2689         // support for VirtualPathProvider
2690         internal void WriteVirtualFile(VirtualFile vf) {
2691             Debug.Trace("WriteVirtualFile", vf.Name);
2692
2693             using (Stream s = vf.Open()) {
2694                 if (UsingHttpWriter) {
2695                     long size = s.Length;
2696
2697                     if (size > 0) {
2698                         // write as memory block
2699                         byte[] fileBytes = new byte[(int)size];
2700                         int bytesRead = s.Read(fileBytes, 0, (int) size);
2701                         _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2702                     }
2703                 }
2704                 else {
2705                     // Write file contents
2706                     WriteStreamAsText(s, 0, -1);
2707                 }
2708             }
2709         }
2710
2711         // Helper method to get absolute physical filename from the argument to WriteFile
2712         private String GetNormalizedFilename(String fn) {
2713             // If it's not a physical path, call MapPath on it
2714             if (!UrlPath.IsAbsolutePhysicalPath(fn)) {
2715                 if (Request != null)
2716                     fn = Request.MapPath(fn); // relative to current request
2717                 else
2718                     fn = HostingEnvironment.MapPath(fn);
2719             }
2720
2721             return fn;
2722         }
2723
2724         // Write file
2725         ///  Writes a named file directly to an HTTP content output stream.
2726         public void WriteFile(String filename) {
2727             if (filename == null) {
2728                 throw new ArgumentNullException("filename");
2729             }
2730
2731             WriteFile(filename, false);
2732         }
2733
2734         /*
2735          * Write file
2736          *
2737          * @param filename file to write
2738          * @readIntoMemory flag to read contents into memory immediately
2739          */
2740
2741         /// <devdoc>
2742         ///    <para> Reads a file into a memory block.</para>
2743         /// </devdoc>
2744         public void WriteFile(String filename, bool readIntoMemory) {
2745             if (filename == null) {
2746                 throw new ArgumentNullException("filename");
2747             }
2748
2749             filename = GetNormalizedFilename(filename);
2750
2751             FileStream f = null;
2752
2753             try {
2754                 f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2755
2756                 if (UsingHttpWriter) {
2757                     long size = f.Length;
2758
2759                     if (size > 0) {
2760                         if (readIntoMemory) {
2761                             // write as memory block
2762                             byte[] fileBytes = new byte[(int)size];
2763                             int bytesRead = f.Read(fileBytes, 0, (int) size);
2764                             _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2765                         }
2766                         else {
2767                             // write as file block
2768                             f.Close(); // close before writing
2769                             f = null;
2770                             _httpWriter.WriteFile(filename, 0, size);
2771                         }
2772                     }
2773                 }
2774                 else {
2775                     // Write file contents
2776                     WriteStreamAsText(f, 0, -1);
2777                 }
2778             }
2779             finally {
2780                 if (f != null)
2781                     f.Close();
2782             }
2783         }
2784
2785
2786         public void TransmitFile(string filename) {
2787             TransmitFile(filename, 0, -1);
2788         }
2789         public void TransmitFile(string filename, long offset, long length) {
2790             if (filename == null) {
2791                 throw new ArgumentNullException("filename");
2792             }
2793             if (offset < 0)
2794                 throw new ArgumentException(SR.GetString(SR.Invalid_range), "offset");
2795             if (length < -1)
2796                 throw new ArgumentException(SR.GetString(SR.Invalid_range), "length");
2797
2798             filename = GetNormalizedFilename(filename);
2799
2800             long size;
2801             using (FileStream f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
2802                 size = f.Length;
2803                 // length of -1 means send rest of file
2804                 if (length == -1) {
2805                     length =  size - offset;
2806                 }
2807                 if (size < offset) {
2808                     throw new ArgumentException(SR.GetString(SR.Invalid_range), "offset");
2809                 }
2810                 else if ((size - offset) < length) {
2811                     throw new ArgumentException(SR.GetString(SR.Invalid_range), "length");
2812                 }
2813                 if (!UsingHttpWriter) {
2814                     WriteStreamAsText(f, offset, length);
2815                     return;
2816                 }
2817             }
2818
2819             if (length > 0) {
2820                 bool supportsLongTransmitFile = (_wr != null && _wr.SupportsLongTransmitFile);
2821
2822                 _httpWriter.TransmitFile(filename, offset, length,
2823                    _context.IsClientImpersonationConfigured || HttpRuntime.IsOnUNCShareInternal, supportsLongTransmitFile);
2824             }
2825         }
2826
2827
2828         private void ValidateFileRange(String filename, long offset, long length) {
2829             FileStream f = null;
2830
2831             try {
2832                 f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2833
2834                 long fileSize = f.Length;
2835
2836                 if (length == -1)
2837                     length = fileSize - offset;
2838
2839                 if (offset < 0 || length > fileSize - offset)
2840                     throw new HttpException(SR.GetString(SR.Invalid_range));
2841             }
2842             finally {
2843                 if (f != null)
2844                     f.Close();
2845             }
2846         }
2847
2848         /*
2849          * Write file
2850          *
2851          * @param filename file to write
2852          * @param offset file offset to start writing
2853          * @param size number of bytes to write
2854          */
2855
2856         /// <devdoc>
2857         ///    <para>Writes a file directly to an HTTP content output stream.</para>
2858         /// </devdoc>
2859         public void WriteFile(String filename, long offset, long size) {
2860             if (filename == null) {
2861                 throw new ArgumentNullException("filename");
2862             }
2863
2864             if (size == 0)
2865                 return;
2866
2867             filename = GetNormalizedFilename(filename);
2868
2869             ValidateFileRange(filename, offset, size);
2870
2871             if (UsingHttpWriter) {
2872                 // HttpWriter can take files -- don't open here (but Demand permission)
2873                 InternalSecurityPermissions.FileReadAccess(filename).Demand();
2874                 _httpWriter.WriteFile(filename, offset, size);
2875             }
2876             else {
2877                 FileStream f = null;
2878
2879                 try {
2880                     f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2881                     WriteStreamAsText(f, offset, size);
2882                 }
2883                 finally {
2884                     if (f != null)
2885                         f.Close();
2886                 }
2887             }
2888         }
2889
2890         /*
2891          * Write file
2892          *
2893          * @param handle file to write
2894          * @param offset file offset to start writing
2895          * @param size number of bytes to write
2896          */
2897
2898         /// <devdoc>
2899         ///    <para>Writes a file directly to an HTTP content output stream.</para>
2900         /// </devdoc>
2901         [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
2902         public void WriteFile(IntPtr fileHandle, long offset, long size) {
2903             if (size <= 0)
2904                 return;
2905
2906             FileStream f = null;
2907
2908             try {
2909                 f = new FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(fileHandle,false), FileAccess.Read);
2910
2911                 if (UsingHttpWriter) {
2912                     long fileSize = f.Length;
2913
2914                     if (size == -1)
2915                         size = fileSize - offset;
2916
2917                     if (offset < 0 || size > fileSize - offset)
2918                         throw new HttpException(SR.GetString(SR.Invalid_range));
2919
2920                     if (offset > 0)
2921                         f.Seek(offset, SeekOrigin.Begin);
2922
2923                     // write as memory block
2924                     byte[] fileBytes = new byte[(int)size];
2925                     int bytesRead = f.Read(fileBytes, 0, (int)size);
2926                     _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2927                 }
2928                 else {
2929                     WriteStreamAsText(f, offset, size);
2930                 }
2931             }
2932             finally {
2933                 if (f != null)
2934                     f.Close();
2935             }
2936         }
2937
2938         /// <devdoc>
2939         ///    <para>Allows HTTP/2 Server Push</para>
2940         /// </devdoc>
2941         public void PushPromise(string path) {
2942             // 
2943
2944
2945             PushPromise(path, method: "GET", headers: null);
2946         }
2947
2948         /// <devdoc>
2949         ///    <para>Allows HTTP/2 Server Push</para>
2950         /// </devdoc>
2951         public void PushPromise(string path, string method, NameValueCollection headers) {
2952             // PushPromise is non-deterministic and application shouldn't have logic that depends on it. 
2953             // It's only purpose is performance advantage in some cases.
2954             // There are many conditions (protocol and implementation) that may cause to 
2955             // ignore the push requests completely.
2956             // The expectation is based on fire-and-forget 
2957
2958             if (path == null) {
2959                 throw new ArgumentNullException("path");
2960             }
2961
2962             if (method == null) {
2963                 throw new ArgumentNullException("method");
2964             }
2965
2966             // Extract an optional query string
2967             string queryString = string.Empty;
2968             int i = path.IndexOf('?');
2969
2970             if (i >= 0) {
2971                 if (i < path.Length - 1) {
2972                     queryString = path.Substring(i + 1);
2973                 }
2974
2975                 // Remove the query string portion from the path
2976                 path = path.Substring(0, i);
2977             }
2978
2979
2980             // Only virtual path is allowed:
2981             // "/path"   - origin relative
2982             // "~/path"  - app relative
2983             // "path"    - request relative
2984             // "../path" - reduced 
2985             if (string.IsNullOrEmpty(path) || !UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
2986                 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_push_promise, path));
2987             }
2988
2989             VirtualPath virtualPath = Request.FilePathObject.Combine(VirtualPath.Create(path));
2990
2991             try {
2992                 if (!HttpRuntime.UseIntegratedPipeline) {
2993                     throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
2994                 }
2995
2996                 // Do push promise
2997                 IIS7WorkerRequest wr = (IIS7WorkerRequest) _wr;
2998                 wr.PushPromise(virtualPath.VirtualPathString, queryString, method, headers);
2999             }
3000             catch (PlatformNotSupportedException e) {
3001                 // Ignore errors if push promise is not supported
3002                 if (Context.TraceIsEnabled) {
3003                     Context.Trace.Write("aspx", "Push promise is not supported", e);
3004                 }
3005             }
3006         }
3007
3008         //
3009         // Deprecated ASP compatibility methods and properties
3010         //
3011
3012
3013         /// <devdoc>
3014         ///    <para>
3015         ///       Same as StatusDescription. Provided only for ASP compatibility.
3016         ///    </para>
3017         /// </devdoc>
3018         public string Status {
3019             get {
3020                 return this.StatusCode.ToString(NumberFormatInfo.InvariantInfo) + " " + this.StatusDescription;
3021             }
3022
3023             set {
3024                 int code = 200;
3025                 String descr = "OK";
3026
3027                 try {
3028                     int i = value.IndexOf(' ');
3029                     code = Int32.Parse(value.Substring(0, i), CultureInfo.InvariantCulture);
3030                     descr = value.Substring(i+1);
3031                 }
3032                 catch {
3033                     throw new HttpException(SR.GetString(SR.Invalid_status_string));
3034                 }
3035
3036                 this.StatusCode = code;
3037                 this.StatusDescription = descr;
3038             }
3039         }
3040
3041
3042         /// <devdoc>
3043         ///    <para>
3044         ///       Same as BufferOutput. Provided only for ASP compatibility.
3045         ///    </para>
3046         /// </devdoc>
3047         public bool Buffer {
3048             get { return this.BufferOutput;}
3049             set { this.BufferOutput = value;}
3050         }
3051
3052
3053         /// <devdoc>
3054         ///    <para>Same as Appendheader. Provided only for ASP compatibility.</para>
3055         /// </devdoc>
3056         public void AddHeader(String name, String value) {
3057             AppendHeader(name, value);
3058         }
3059
3060         /*
3061          * Cancelles handler processing of the current request
3062          * throws special [non-]exception uncatchable by the user code
3063          * to tell application to stop module execution.
3064          */
3065
3066         /// <devdoc>
3067         ///    <para>Sends all currently buffered output to the client then closes the
3068         ///       socket connection.</para>
3069         /// </devdoc>
3070         public void End() {
3071             if (_context.IsInCancellablePeriod) {
3072                 AbortCurrentThread();
3073             }
3074             else {
3075                 // when cannot abort execution, flush and supress further output
3076                 _endRequiresObservation = true;
3077
3078                 if (!_flushing) { // ignore Reponse.End while flushing (in OnPreSendHeaders)
3079                     Flush();
3080                     _ended = true;
3081
3082                     if (_context.ApplicationInstance != null) {
3083                         _context.ApplicationInstance.CompleteRequest();
3084                     }
3085                 }
3086             }
3087         }
3088
3089         // Aborts the current thread if Response.End was called and not yet observed.
3090         internal void ObserveResponseEndCalled() {
3091             if (_endRequiresObservation) {
3092                 _endRequiresObservation = false;
3093                 AbortCurrentThread();
3094             }
3095         }
3096
3097         [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Known issue, but required for proper operation of ASP.NET.")]
3098         [SecurityPermission(SecurityAction.Assert, ControlThread = true)]
3099         private static void AbortCurrentThread() {
3100             Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
3101         }
3102
3103         /*
3104          * ASP compatible caching properties
3105          */
3106
3107
3108         /// <devdoc>
3109         ///    <para>
3110         ///       Gets or sets the time, in minutes, until cached
3111         ///       information will be removed from the cache. Provided for ASP compatiblility. Use
3112         ///       the <see cref='System.Web.HttpResponse.Cache'/>
3113         ///       Property instead.
3114         ///    </para>
3115         /// </devdoc>
3116         public int Expires {
3117             get {
3118                 return _expiresInMinutes;
3119             }
3120             set {
3121                 if (!_expiresInMinutesSet || value < _expiresInMinutes) {
3122                     _expiresInMinutes = value;
3123                     Cache.SetExpires(_context.Timestamp + new TimeSpan(0, _expiresInMinutes, 0));
3124                 }
3125             }
3126         }
3127
3128
3129         /// <devdoc>
3130         ///    <para>
3131         ///       Gets or sets the absolute time that cached information
3132         ///       will be removed from the cache. Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
3133         ///       property instead.
3134         ///    </para>
3135         /// </devdoc>
3136         public DateTime ExpiresAbsolute {
3137             get {
3138                 return _expiresAbsolute;
3139             }
3140             set {
3141                 if (!_expiresAbsoluteSet || value < _expiresAbsolute) {
3142                     _expiresAbsolute = value;
3143                     Cache.SetExpires(_expiresAbsolute);
3144                 }
3145             }
3146         }
3147
3148
3149         /// <devdoc>
3150         ///    <para>
3151         ///       Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
3152         ///       property instead.
3153         ///    </para>
3154         /// </devdoc>
3155         public string CacheControl {
3156             get {
3157                 if (_cacheControl == null) {
3158                     // the default
3159                     return "private";
3160                 }
3161
3162                 return _cacheControl;
3163             }
3164             set {
3165                 if (String.IsNullOrEmpty(value)) {
3166                     _cacheControl = null;
3167                     Cache.SetCacheability(HttpCacheability.NoCache);
3168                 }
3169                 else if (StringUtil.EqualsIgnoreCase(value, "private")) {
3170                     _cacheControl = value;
3171                     Cache.SetCacheability(HttpCacheability.Private);
3172                 }
3173                 else if (StringUtil.EqualsIgnoreCase(value, "public")) {
3174                     _cacheControl = value;
3175                     Cache.SetCacheability(HttpCacheability.Public);
3176                 }
3177                 else if (StringUtil.EqualsIgnoreCase(value, "no-cache")) {
3178                     _cacheControl = value;
3179                     Cache.SetCacheability(HttpCacheability.NoCache);
3180                 }
3181                 else {
3182                     throw new ArgumentException(SR.GetString(SR.Invalid_value_for_CacheControl, value));
3183                 }
3184             }
3185         }
3186
3187         internal void SetAppPathModifier(string appPathModifier) {
3188             if (appPathModifier != null && (
3189                 appPathModifier.Length == 0 ||
3190                 appPathModifier[0] == '/' ||
3191                 appPathModifier[appPathModifier.Length - 1] == '/')) {
3192
3193                 throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "appPathModifier"));
3194             }
3195
3196             _appPathModifier = appPathModifier;
3197
3198             Debug.Trace("ClientUrl", "*** SetAppPathModifier (" + appPathModifier + ") ***");
3199         }
3200
3201
3202         public string ApplyAppPathModifier(string virtualPath) {
3203 #if DBG
3204             string originalUrl = virtualPath;
3205 #endif
3206             object ch = _context.CookielessHelper; // This ensures that the cookieless-helper is initialized and applies the AppPathModifier
3207             if (virtualPath == null)
3208                 return null;
3209
3210             if (UrlPath.IsRelativeUrl(virtualPath)) {
3211                 // DevDiv 173208: RewritePath returns an HTTP 500 error code when requested with certain user agents
3212                 // We should use ClientBaseDir instead of FilePathObject.
3213                 virtualPath = UrlPath.Combine(Request.ClientBaseDir.VirtualPathString, virtualPath);
3214             }
3215             else {
3216                 // ignore paths with http://server/... or //
3217                 if (!UrlPath.IsRooted(virtualPath) || virtualPath.StartsWith("//", StringComparison.Ordinal)) {
3218                     return virtualPath;
3219                 }
3220
3221                 virtualPath = UrlPath.Reduce(virtualPath);
3222             }
3223
3224             if (_appPathModifier == null || virtualPath.IndexOf(_appPathModifier, StringComparison.Ordinal) >= 0) {
3225 #if DBG
3226                 Debug.Trace("ClientUrl", "*** ApplyAppPathModifier (" + originalUrl + ") --> " + virtualPath + " ***");
3227 #endif
3228                 return virtualPath;
3229             }
3230             
3231             string appPath = HttpRuntime.AppDomainAppVirtualPathString;
3232
3233             int compareLength = appPath.Length;
3234             bool isVirtualPathShort = (virtualPath.Length == appPath.Length - 1);
3235             if (isVirtualPathShort) {
3236                 compareLength--;
3237             }
3238
3239             // String.Compare will throw exception if there aren't compareLength characters
3240             if (virtualPath.Length < compareLength) {
3241                 return virtualPath;
3242             }
3243
3244             if (!StringUtil.EqualsIgnoreCase(virtualPath, 0, appPath, 0, compareLength)) {
3245                 return virtualPath;
3246             }
3247
3248             if (isVirtualPathShort) {
3249                 virtualPath += "/";
3250             }
3251
3252             Debug.Assert(virtualPath.Length >= appPath.Length);
3253             if (virtualPath.Length == appPath.Length) {
3254                 virtualPath = virtualPath.Substring(0, appPath.Length) + _appPathModifier + "/";
3255             }
3256             else {
3257                 virtualPath =
3258                     virtualPath.Substring(0, appPath.Length) +
3259                     _appPathModifier +
3260                     "/" +
3261                     virtualPath.Substring(appPath.Length);
3262             }
3263 #if DBG
3264             Debug.Trace("ClientUrl", "*** ApplyAppPathModifier (" + originalUrl + ") --> " + virtualPath + " ***");
3265 #endif
3266
3267             return virtualPath;
3268         }
3269
3270         internal String RemoveAppPathModifier(string virtualPath) {
3271             if (String.IsNullOrEmpty(_appPathModifier))
3272                 return virtualPath;
3273
3274             int pos = virtualPath.IndexOf(_appPathModifier, StringComparison.Ordinal);
3275
3276             if (pos <= 0 || virtualPath[pos-1] != '/')
3277                 return virtualPath;
3278
3279             return virtualPath.Substring(0, pos-1) + virtualPath.Substring(pos + _appPathModifier.Length);
3280         }
3281
3282         internal bool UsePathModifier {
3283             get {
3284                 return !String.IsNullOrEmpty(_appPathModifier);
3285             }
3286         }
3287
3288         private String ConvertToFullyQualifiedRedirectUrlIfRequired(String url) {
3289             HttpRuntimeSection runtimeConfig = RuntimeConfig.GetConfig(_context).HttpRuntime;
3290             if (    runtimeConfig.UseFullyQualifiedRedirectUrl ||
3291                     (Request != null && (string)Request.Browser["requiresFullyQualifiedRedirectUrl"] == "true")) {
3292                 return (new Uri(Request.Url, url)).AbsoluteUri ;
3293             }
3294             else {
3295                 return url;
3296             }
3297         }
3298
3299         private String UrlEncodeIDNSafe(String url) {
3300             // Bug 86594: Should not encode the domain part of the url. For example,
3301             // http://Ãœbersite/Ãœberpage.aspx should only encode the 2nd Ãœ.
3302             // To accomplish this we must separate the scheme+host+port portion of the url from the path portion,
3303             // encode the path portion, then reconstruct the url.
3304             Debug.Assert(!url.Contains("?"), "Querystring should have been stripped off.");
3305
3306             string schemeAndAuthority;
3307             string path;
3308             string queryAndFragment;
3309             bool isValidUrl = UriUtil.TrySplitUriForPathEncode(url, out schemeAndAuthority, out path, out queryAndFragment, checkScheme: true);
3310
3311             if (isValidUrl) {
3312                 // only encode the path portion
3313                 return schemeAndAuthority + HttpEncoderUtility.UrlEncodeSpaces(HttpUtility.UrlEncodeNonAscii(path, Encoding.UTF8)) + queryAndFragment;
3314             }
3315             else {
3316                 // encode the entire URL
3317                 return HttpEncoderUtility.UrlEncodeSpaces(HttpUtility.UrlEncodeNonAscii(url, Encoding.UTF8));
3318             }
3319         }
3320
3321         private String UrlEncodeRedirect(String url) {
3322             // convert all non-ASCII chars before ? to %XX using UTF-8 and
3323             // after ? using Response.ContentEncoding
3324
3325             int iqs = url.IndexOf('?');
3326
3327             if (iqs >= 0) {
3328                 Encoding qsEncoding = (Request != null) ? Request.ContentEncoding : ContentEncoding;
3329                 url = UrlEncodeIDNSafe(url.Substring(0, iqs)) + HttpUtility.UrlEncodeNonAscii(url.Substring(iqs), qsEncoding);
3330             }
3331             else {
3332                 url = UrlEncodeIDNSafe(url);
3333             }
3334
3335             return url;
3336         }
3337
3338         internal void UpdateNativeResponse(bool sendHeaders)
3339         {
3340             IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
3341
3342             if (null == iis7WorkerRequest) {
3343                 return;
3344             }
3345
3346             // WOS 1841024 - Don't set _suppressContent to true for HEAD requests.  IIS needs the content
3347             // in order to correctly set the Content-Length header.
3348             // WOS 1634512 - need to clear buffers if _ended == true
3349             // WOS 1850019 - Breaking Change: ASP.NET v2.0: Content-Length is not correct for pages that call HttpResponse.SuppressContent
3350             if ((_suppressContent && Request != null && Request.HttpVerb != HttpVerb.HEAD) || _ended)
3351                 Clear();
3352
3353             bool needPush = false;
3354             // NOTE: This also sets the response encoding on the HttpWriter
3355             long bufferedLength = _httpWriter.GetBufferedLength();
3356
3357             //
3358             // Set headers and status
3359             //
3360             if (!_headersWritten)
3361             {
3362                 //
3363                 // Set status
3364                 //
3365                 // VSWhidbey 270635: We need to reset the status code for mobile devices.
3366                 if (UseAdaptiveError) {
3367
3368                     // VSWhidbey 288054: We should change the status code for cases
3369                     // that cannot be handled by mobile devices
3370                     // 4xx for Client Error and 5xx for Server Error in HTTP spec
3371                     int statusCode = StatusCode;
3372                     if (statusCode >= 400 && statusCode < 600) {
3373                         this.StatusCode = 200;
3374                     }
3375                 }
3376
3377                 // DevDiv #782830: Provide a hook where the application can change the response status code
3378                 // or response headers.
3379                 if (sendHeaders && !_onSendingHeadersSubscriptionQueue.IsEmpty) {
3380                     _onSendingHeadersSubscriptionQueue.FireAndComplete(cb => cb(Context));
3381                 }
3382
3383                 if (_statusSet) {
3384                     _wr.SendStatus(this.StatusCode, this.SubStatusCode, this.StatusDescription);
3385                     _statusSet = false;
3386                 }
3387
3388                 //
3389                 //  Set headers
3390                 //
3391                 if (!_suppressHeaders && !_clientDisconnected)
3392                 {
3393                     if (sendHeaders) {
3394                         EnsureSessionStateIfNecessary();
3395                     }
3396
3397                     // If redirect location set, write it through to IIS as a header
3398                     if (_redirectLocation != null && _redirectLocationSet) {
3399                         HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3400                         headers.Set("Location", _redirectLocation);
3401                         _redirectLocationSet = false;
3402                     }
3403
3404                     // Check if there is buffered response
3405                     bool responseBuffered = bufferedLength > 0 || iis7WorkerRequest.IsResponseBuffered();
3406
3407                     //
3408                     // Generate Content-Type
3409                     //
3410                     if (_contentType != null                                              // Valid Content-Type
3411                         && (_contentTypeSetByManagedCaller                                // Explicitly set by managed caller 
3412                             || (_contentTypeSetByManagedHandler && responseBuffered))) {  // Implicitly set by managed handler and response is non-empty
3413                         HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3414                         String contentType = AppendCharSetToContentType(_contentType);
3415                         headers.Set("Content-Type", contentType);
3416                     }
3417
3418                     //
3419                     // If cookies have been added/changed, set the corresponding headers
3420                     //
3421                     GenerateResponseHeadersForCookies();
3422
3423                     // Not calling WriteHeaders headers in Integrated mode.
3424                     // Instead, most headers are generated when the handler runs,
3425                     // or on demand as necessary.
3426                     // The only exception are the cache policy headers.
3427                     if (sendHeaders) {
3428
3429                         SuppressCachingCookiesIfNecessary();
3430
3431                         if (_cachePolicy != null) {
3432                             if (_cachePolicy.IsModified()) {
3433                                 ArrayList cacheHeaders = new ArrayList();
3434                                 _cachePolicy.GetHeaders(cacheHeaders, this);
3435                                 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3436                                 foreach (HttpResponseHeader header in cacheHeaders) {
3437                                     // set and override the header
3438                                     headers.Set(header.Name, header.Value);
3439                                 }
3440                             }
3441                         }
3442
3443                         needPush = true;
3444                     }
3445                 }
3446             }
3447
3448             if (_flushing && !_filteringCompleted) {
3449                 _httpWriter.FilterIntegrated(false, iis7WorkerRequest);
3450                 bufferedLength = _httpWriter.GetBufferedLength();
3451             }
3452
3453             if (!_clientDisconnected && (bufferedLength > 0 || needPush)) {
3454
3455                 if (bufferedLength == 0 ) {
3456                     if (_httpWriter.IgnoringFurtherWrites) {
3457                         return;
3458                     }
3459                 }
3460
3461                 // push HttpWriter buffers to worker request
3462                 _httpWriter.Send(_wr);
3463                 // push buffers through into native
3464                 iis7WorkerRequest.PushResponseToNative();
3465                 // dispose them (since they're copied or
3466                 // owned by native request)
3467                 _httpWriter.DisposeIntegratedBuffers();
3468             }
3469         }
3470
3471         private void ClearNativeResponse(bool clearEntity, bool clearHeaders, IIS7WorkerRequest wr) {
3472             wr.ClearResponse(clearEntity, clearHeaders);
3473             if (clearEntity) {
3474                 _httpWriter.ClearSubstitutionBlocks();
3475             }
3476         }
3477
3478         private void SuppressCachingCookiesIfNecessary() {
3479             // MSRC 11855 (DevDiv 297240 / 362405)
3480             // We should suppress caching cookies if non-shareable cookies are
3481             // present in the response. Since these cookies can cary sensitive information, 
3482             // we should set Cache-Control: no-cache=set-cookie if there is such cookie
3483             // This prevents all well-behaved caches (both intermediary proxies and any local caches
3484             // on the client) from storing this sensitive information.
3485             // 
3486             // Additionally, we should not set this header during an SSL request, as certain versions
3487             // of IE don't handle it properly and simply refuse to render the page. More info:
3488             // http://blogs.msdn.com/b/ieinternals/archive/2009/10/02/internet-explorer-cannot-download-over-https-when-no-cache.aspx
3489             //
3490             // Finally, we don't need to set 'no-cache' if the response is not publicly cacheable,
3491             // as ASP.NET won't cache the response (due to the cookies) and proxies won't cache
3492             // the response (due to Cache-Control: private).
3493             // If _cachePolicy isn't set, then Cache.GetCacheability() will contruct a default one (which causes Cache-Control: private)
3494             if (!Request.IsSecureConnection && ContainsNonShareableCookies() && Cache.GetCacheability() == HttpCacheability.Public) {
3495                 Cache.SetCacheability(HttpCacheability.NoCache, "Set-Cookie");
3496             }
3497
3498             // if there are any cookies, do not kernel cache the response
3499             if (_cachePolicy != null && _cookies != null && _cookies.Count != 0) {
3500                 _cachePolicy.SetHasSetCookieHeader();
3501                 // In integrated mode, the cookies will eventually be sent to IIS via IIS7WorkerRequest.SetUnknownResponseHeader,
3502                 // where we will disable both HTTP.SYS kernel cache and IIS user mode cache (DevDiv 113142 & 255268). In classic
3503                 // mode, the cookies will be sent to IIS via ISAPIWorkerRequest.SendUnknownResponseHeader and 
3504                 // ISAPIWorkerRequest.SendKnownResponseHeader (DevDiv 113142), where we also disables the kernel cache. So the 
3505                 // call of DisableKernelCache below is not really needed.
3506                 DisableKernelCache();
3507             }
3508         }
3509
3510         private void EnsureSessionStateIfNecessary() {
3511             // Ensure the session state is in complete state before sending the response headers
3512             // Due to optimization and delay initialization sometimes we create and store the session state id in ReleaseSessionState.
3513             // But it's too late in case of Flush. Session state id must be written (if used) before sending the headers.
3514             if (AppSettings.EnsureSessionStateLockedOnFlush) {
3515                 _context.EnsureSessionStateIfNecessary();
3516             }
3517         }
3518     }
3519
3520     internal enum CacheDependencyType {
3521         Files,
3522         CacheItems,
3523         VirtualPaths
3524     }
3525
3526     struct ResponseDependencyList {
3527         private ArrayList   _dependencies;
3528         private string[]    _dependencyArray;
3529         private DateTime    _oldestDependency;
3530         private string      _requestVirtualPath;
3531
3532         internal void AddDependency(string item, string argname) {
3533             if (item == null) {
3534                 throw new ArgumentNullException(argname);
3535             }
3536
3537             _dependencyArray = null;
3538
3539             if (_dependencies == null) {
3540                 _dependencies = new ArrayList(1);
3541             }
3542
3543             DateTime utcNow = DateTime.UtcNow;
3544
3545             _dependencies.Add(new ResponseDependencyInfo(
3546                     new string[] {item}, utcNow));
3547
3548             // _oldestDependency is initialized to MinValue and indicates that it must always be set
3549             if (_oldestDependency == DateTime.MinValue || utcNow < _oldestDependency)
3550                 _oldestDependency = utcNow;
3551         }
3552
3553         internal void AddDependencies(ArrayList items, string argname) {
3554             if (items == null) {
3555                 throw new ArgumentNullException(argname);
3556             }
3557
3558             string[] a = (string[]) items.ToArray(typeof(string));
3559             AddDependencies(a, argname, false);
3560         }
3561
3562         internal void AddDependencies(string[] items, string argname) {
3563             AddDependencies(items, argname, true);
3564         }
3565
3566         internal void AddDependencies(string[] items, string argname, bool cloneArray) {
3567             AddDependencies(items, argname, cloneArray, DateTime.UtcNow);
3568         }
3569
3570         internal void AddDependencies(string[] items, string argname, bool cloneArray, string requestVirtualPath) {
3571             if (requestVirtualPath == null)
3572                 throw new ArgumentNullException("requestVirtualPath");
3573
3574             _requestVirtualPath = requestVirtualPath;
3575             AddDependencies(items, argname, cloneArray, DateTime.UtcNow);
3576         }
3577
3578         internal void AddDependencies(string[] items, string argname, bool cloneArray, DateTime utcDepTime) {
3579             if (items == null) {
3580                 throw new ArgumentNullException(argname);
3581             }
3582
3583             string [] itemsLocal;
3584
3585             if (cloneArray) {
3586                 itemsLocal = (string[]) items.Clone();
3587             }
3588             else {
3589                 itemsLocal = items;
3590             }
3591
3592             foreach (string item in itemsLocal) {
3593                 if (String.IsNullOrEmpty(item)) {
3594                     throw new ArgumentNullException(argname);
3595                 }
3596             }
3597
3598             _dependencyArray = null;
3599
3600             if (_dependencies == null) {
3601                 _dependencies = new ArrayList(1);
3602             }
3603
3604             _dependencies.Add(new ResponseDependencyInfo(itemsLocal, utcDepTime));
3605
3606             // _oldestDependency is initialized to MinValue and indicates that it must always be set
3607             if (_oldestDependency == DateTime.MinValue || utcDepTime < _oldestDependency)
3608                 _oldestDependency = utcDepTime;
3609         }
3610
3611         internal bool HasDependencies() {
3612             if (_dependencyArray == null && _dependencies == null)
3613                 return false;
3614
3615             return true;
3616         }
3617
3618         internal string[] GetDependencies() {
3619             if (_dependencyArray == null && _dependencies != null) {
3620                 int size = 0;
3621                 foreach (ResponseDependencyInfo info in _dependencies) {
3622                     size += info.items.Length;
3623                 }
3624
3625                 _dependencyArray = new string[size];
3626
3627                 int index = 0;
3628                 foreach (ResponseDependencyInfo info in _dependencies) {
3629                     int length = info.items.Length;
3630                     Array.Copy(info.items, 0, _dependencyArray, index, length);
3631                     index += length;
3632                 }
3633             }
3634
3635             return _dependencyArray;
3636         }
3637
3638         // The caller of this method must dispose the cache dependencies
3639         internal CacheDependency CreateCacheDependency(CacheDependencyType dependencyType, CacheDependency dependency) {
3640             if (_dependencies != null) {
3641                 if (dependencyType == CacheDependencyType.Files
3642                     || dependencyType == CacheDependencyType.CacheItems) {
3643                     foreach (ResponseDependencyInfo info in _dependencies) {
3644                         CacheDependency dependencyOld = dependency;
3645                         try {
3646                             if (dependencyType == CacheDependencyType.Files) {
3647                                 dependency = new CacheDependency(0, info.items, null, dependencyOld, info.utcDate);
3648                             }
3649                             else {
3650                                 // We create a "public" CacheDepdency here, since the keys are for public items.
3651                                 dependency = new CacheDependency(null, info.items, dependencyOld,
3652                                                                  DateTimeUtil.ConvertToLocalTime(info.utcDate));
3653                             }
3654                         }
3655                         finally {
3656                             if (dependencyOld != null) {
3657                                 dependencyOld.Dispose();
3658                             }
3659                         }
3660                     }
3661                 }
3662                 else {
3663                     CacheDependency virtualDependency = null;
3664                     VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
3665                     if (vpp != null && _requestVirtualPath != null) {
3666                         virtualDependency = vpp.GetCacheDependency(_requestVirtualPath, GetDependencies(), _oldestDependency);
3667                     }
3668                     if (virtualDependency != null) {
3669                         AggregateCacheDependency tempDep = new AggregateCacheDependency();
3670                         tempDep.Add(virtualDependency);
3671                         if (dependency != null) {
3672                             tempDep.Add(dependency);
3673                         }
3674                         dependency = tempDep;
3675                     }
3676                 }
3677             }
3678
3679             return dependency;
3680         }
3681     }
3682
3683     internal class ResponseDependencyInfo {
3684         internal readonly string[]    items;
3685         internal readonly DateTime    utcDate;
3686
3687         internal ResponseDependencyInfo(string[] items, DateTime utcDate) {
3688             this.items = items;
3689             this.utcDate = utcDate;
3690         }
3691     }
3692 }
3693