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