1 //------------------------------------------------------------------------------
2 // <copyright file="HttpResponse.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
10 namespace System.Web {
13 using System.Threading;
14 using System.Threading.Tasks;
15 using System.Runtime.Serialization;
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;
26 using System.Configuration;
27 using System.Security.Permissions;
28 using System.Web.Management;
29 using System.Diagnostics.CodeAnalysis;
33 /// <para>Used in HttpResponse.WriteSubstitution.</para>
35 public delegate String HttpResponseSubstitutionCallback(HttpContext context);
39 /// <para> Enables type-safe server to browser communication. Used to
40 /// send Http output to a client.</para>
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
48 private HttpHeaderCollection _headers; // response header collection (IIS7+)
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;
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;
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;
97 private ErrorFormatter _overrideErrorFormatter;
100 int _expiresInMinutes;
101 bool _expiresInMinutesSet;
102 DateTime _expiresAbsolute;
103 bool _expiresAbsoluteSet;
104 string _cacheControl;
106 private bool _statusSet;
107 private int _subStatusCode;
108 private bool _versionHeaderSent;
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;
118 bool _transferEncodingSet;
121 // OnSendingHeaders pseudo-event
122 private SubscriptionQueue<Action<HttpContext>> _onSendingHeadersSubscriptionQueue = new SubscriptionQueue<Action<HttpContext>>();
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;
129 private static readonly String _redirectQueryString = "?" + RedirectQueryStringAssignment;
130 private static readonly String _redirectQueryStringInline = RedirectQueryStringAssignment + "&";
132 internal static event EventHandler Redirecting;
134 internal HttpContext Context {
135 get { return _context; }
136 set { _context = value; }
139 internal HttpRequest Request {
141 if (_context == null)
143 return _context.Request;
148 * Internal package visible constructor to create responses that
149 * have HttpWorkerRequest
151 * @param wr Worker Request
153 internal HttpResponse(HttpWorkerRequest wr, HttpContext context) {
156 // HttpWriter is created in InitResponseWriter
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) {
167 private bool UsingHttpWriter {
169 return (_httpWriter != null && _writer == _httpWriter);
173 internal void SetAllocatorProvider(IAllocatorProvider allocator) {
174 if (_httpWriter != null) {
175 _httpWriter.AllocatorProvider = allocator;
182 internal void Dispose() {
184 if (_httpWriter != null)
185 _httpWriter.RecycleBuffers();
186 // recycle dependencies
187 if (_cacheDependencyForResponse != null) {
188 _cacheDependencyForResponse.Dispose();
189 _cacheDependencyForResponse = null;
191 if (_userAddedDependencies != null) {
192 foreach (CacheDependency dep in _userAddedDependencies) {
195 _userAddedDependencies = null;
199 internal void InitResponseWriter() {
200 if (_httpWriter == null) {
201 _httpWriter = new HttpWriter(this);
203 _writer = _httpWriter;
208 // Private helper methods
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();
220 public bool HeadersWritten {
221 get { return _headersWritten; }
222 internal set { _headersWritten = value; }
225 internal ArrayList GenerateResponseHeadersIntegrated(bool forCache) {
226 ArrayList headers = new ArrayList();
227 HttpHeaderCollection responseHeaders = Headers as HttpHeaderCollection;
230 // copy all current response headers
231 foreach(String key in responseHeaders)
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)) {
248 if ( headerId >= 0 ) {
249 headers.Add(new HttpResponseHeader(headerId, responseHeaders[key]));
252 headers.Add(new HttpResponseHeader(key, responseHeaders[key]));
259 internal void GenerateResponseHeadersForCookies()
261 if (_cookies == null || (_cookies.Count == 0 && !_cookies.Changed))
262 return; // no cookies exist
264 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
265 HttpResponseHeader cookieHeader = null;
266 HttpCookie cookie = null;
267 bool needToReset = false;
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)
278 for(int c = 0; c < _cookies.Count; c++)
280 cookie = _cookies[c];
282 if (!cookie.IsInResponseHeader) {
283 // if a cookie was added, we generate a Set-Cookie header for it
284 cookieHeader = cookie.GetSetCookieHeader(_context);
285 headers.SetHeader(cookieHeader.Name, cookieHeader.Value, false);
286 cookie.IsInResponseHeader = true;
288 cookie.Added = false;
289 cookie.Changed = false;
291 else if (cookie.Changed) {
292 // if a cookie has changed, we need to clear all cookie
293 // headers and re-write them all since we cant delete
294 // specific existing cookies
302 if (_cookies.Changed || needToReset)
304 // delete all set cookie headers
305 headers.Remove("Set-Cookie");
307 // write all the cookies again
308 for(int c = 0; c < _cookies.Count; c++)
310 // generate a Set-Cookie header for each cookie
311 cookie = _cookies[c];
312 cookieHeader = cookie.GetSetCookieHeader(_context);
313 headers.SetHeader(cookieHeader.Name, cookieHeader.Value, false);
314 cookie.IsInResponseHeader = true;
315 cookie.Added = false;
316 cookie.Changed = false;
319 _cookies.Changed = false;
323 internal void GenerateResponseHeadersForHandler()
325 if ( !(_wr is IIS7WorkerRequest) ) {
329 String versionHeader = null;
331 // Generate the default headers associated with an ASP.NET handler
332 if (!_headersWritten && !_handlerHeadersGenerated) {
334 // The "sendCacheControlHeader" is default to true, but a false setting in either
335 // the <httpRuntime> section (legacy) or the <outputCache> section (current) will disable
336 // sending of that header.
337 RuntimeConfig config = RuntimeConfig.GetLKGConfig(_context);
339 HttpRuntimeSection runtimeConfig = config.HttpRuntime;
340 if (runtimeConfig != null) {
341 versionHeader = runtimeConfig.VersionHeader;
342 _sendCacheControlHeader = runtimeConfig.SendCacheControlHeader;
345 OutputCacheSection outputCacheConfig = config.OutputCache;
346 if (outputCacheConfig != null) {
347 _sendCacheControlHeader &= outputCacheConfig.SendCacheControlHeader;
350 // DevDiv #406078: Need programmatic way of disabling "Cache-Control: private" response header.
351 if (SuppressDefaultCacheControlHeader) {
352 _sendCacheControlHeader = false;
355 // Ensure that cacheability is set to cache-control: private
356 // if it is not explicitly set
357 if (_sendCacheControlHeader && !_cacheControlHeaderAdded) {
358 Headers.Set("Cache-Control", "private");
361 // set the version header
362 if (!String.IsNullOrEmpty(versionHeader)) {
363 Headers.Set("X-AspNet-Version", versionHeader);
366 // Force content-type generation
367 _contentTypeSetByManagedHandler = true;
370 _handlerHeadersGenerated = true;
375 internal ArrayList GenerateResponseHeaders(bool forCache) {
376 ArrayList headers = new ArrayList();
377 bool sendCacheControlHeader = HttpRuntimeSection.DefaultSendCacheControlHeader;
379 // ASP.NET version header
382 if (!_versionHeaderSent) {
383 String versionHeader = null;
385 // The "sendCacheControlHeader" is default to true, but a false setting in either
386 // the <httpRuntime> section (legacy) or the <outputCache> section (current) will disable
387 // sending of that header.
388 RuntimeConfig config = RuntimeConfig.GetLKGConfig(_context);
390 HttpRuntimeSection runtimeConfig = config.HttpRuntime;
391 if (runtimeConfig != null) {
392 versionHeader = runtimeConfig.VersionHeader;
393 sendCacheControlHeader = runtimeConfig.SendCacheControlHeader;
396 OutputCacheSection outputCacheConfig = config.OutputCache;
397 if (outputCacheConfig != null) {
398 sendCacheControlHeader &= outputCacheConfig.SendCacheControlHeader;
401 if (!String.IsNullOrEmpty(versionHeader)) {
402 headers.Add(new HttpResponseHeader("X-AspNet-Version", versionHeader));
405 _versionHeaderSent = true;
410 if (_customHeaders != null) {
411 int numCustomHeaders = _customHeaders.Count;
412 for (int i = 0; i < numCustomHeaders; i++)
413 headers.Add(_customHeaders[i]);
416 // location of redirect
417 if (_redirectLocation != null) {
418 headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderLocation, _redirectLocation));
421 // don't include headers that the cache changes or omits on a cache hit
424 if (_cookies != null) {
425 int numCookies = _cookies.Count;
427 for (int i = 0; i < numCookies; i++) {
428 headers.Add(_cookies[i].GetSetCookieHeader(Context));
433 if (_cachePolicy != null && _cachePolicy.IsModified()) {
434 _cachePolicy.GetHeaders(headers, this);
437 if (_cacheHeaders != null) {
438 headers.AddRange(_cacheHeaders);
442 * Ensure that cacheability is set to cache-control: private
443 * if it is not explicitly set.
445 if (!_cacheControlHeaderAdded && sendCacheControlHeader) {
446 headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderCacheControl, "private"));
454 if ( _statusCode != 204 && _contentType != null) {
455 String contentType = AppendCharSetToContentType( _contentType );
456 headers.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderContentType, contentType));
463 internal string AppendCharSetToContentType(string contentType)
465 String newContentType = contentType;
467 // charset=xxx logic -- append if
468 // not there already and
469 // custom set or response encoding used by http writer to convert bytes to chars
470 if (_customCharSet || (_httpWriter != null && _httpWriter.ResponseEncodingUsed)) {
471 if (contentType.IndexOf("charset=", StringComparison.Ordinal) < 0) {
472 String charset = Charset;
473 if (charset.Length > 0) { // not suppressed
474 newContentType = contentType + "; charset=" + charset;
479 return newContentType;
482 internal bool UseAdaptiveError {
484 return _useAdaptiveError;
487 _useAdaptiveError = value;
491 private void WriteHeaders() {
495 // Fire pre-send headers event
497 if (_context != null && _context.ApplicationInstance != null) {
498 _context.ApplicationInstance.RaiseOnPreSendRequestHeaders();
502 // VSWhidbey 270635: We need to reset the status code for mobile devices.
503 if (UseAdaptiveError) {
505 // VSWhidbey 288054: We should change the status code for cases
506 // that cannot be handled by mobile devices
507 // 4xx for Client Error and 5xx for Server Error in HTTP spec
508 int statusCode = StatusCode;
509 if (statusCode >= 400 && statusCode < 600) {
510 this.StatusCode = 200;
514 // generate headers before we touch the WorkerRequest since header generation might fail,
515 // and we don't want to have touched the WR if this happens
516 ArrayList headers = GenerateResponseHeaders(false);
518 _wr.SendStatus(this.StatusCode, this.StatusDescription);
522 // unicode messes up the response badly
523 Debug.Assert(!this.HeaderEncoding.Equals(Encoding.Unicode));
524 _wr.SetHeaderEncoding(this.HeaderEncoding);
527 HttpResponseHeader header = null;
528 int n = (headers != null) ? headers.Count : 0;
529 for (int i = 0; i < n; i++)
531 header = headers[i] as HttpResponseHeader;
536 internal int GetBufferedLength() {
537 // if length is greater than Int32.MaxValue, Convert.ToInt32 will throw.
538 // This is okay until we support large response sizes
539 return (_httpWriter != null) ? Convert.ToInt32(_httpWriter.GetBufferedLength()) : 0;
542 private static byte[] s_chunkSuffix = new byte[2] { (byte)'\r', (byte)'\n'};
543 private static byte[] s_chunkEnd = new byte[5] { (byte)'0', (byte)'\r', (byte)'\n', (byte)'\r', (byte)'\n'};
545 private void Flush(bool finalFlush, bool async = false) {
546 // Already completed or inside Flush?
547 if (_completed || _flushing)
550 // Special case for non HTTP Writer
551 if (_httpWriter == null) {
556 // Avoid recursive flushes
559 bool needToClearBuffers = false;
562 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
563 if (iis7WorkerRequest != null) {
564 // generate the handler headers if flushing
565 GenerateResponseHeadersForHandler();
567 // Push buffers across to native side and explicitly flush.
568 // IIS7 handles the chunking as necessary so we can omit that logic
569 UpdateNativeResponse(true /*sendHeaders*/);
573 // force a synchronous send
574 iis7WorkerRequest.ExplicitFlush();
577 // always set after flush, successful or not
578 _headersWritten = true;
585 long bufferedLength = 0;
591 if (!_headersWritten) {
592 if (!_suppressHeaders && !_clientDisconnected) {
593 EnsureSessionStateIfNecessary();
596 bufferedLength = _httpWriter.GetBufferedLength();
598 // suppress content-type for empty responses
599 if (!_contentLengthSet && bufferedLength == 0 && _httpWriter != null)
602 SuppressCachingCookiesIfNecessary();
604 // generate response headers
607 // recalculate as sending headers might change it (PreSendHeaders)
608 bufferedLength = _httpWriter.GetBufferedLength();
610 // Calculate content-length if not set explicitely
611 // WOS #1380818: Content-Length should not be set for response with 304 status (HTTP.SYS doesn't, and HTTP 1.1 spec implies it)
612 if (!_contentLengthSet && _statusCode != 304)
613 _wr.SendCalculatedContentLength(bufferedLength);
616 // Check if need chunking for HTTP/1.1
617 if (!_contentLengthSet && !_transferEncodingSet && _statusCode == 200) {
618 String protocol = _wr.GetHttpVersion();
620 if (protocol != null && protocol.Equals("HTTP/1.1")) {
621 AppendHeader(new HttpResponseHeader(HttpWorkerRequest.HeaderTransferEncoding, "chunked"));
625 bufferedLength = _httpWriter.GetBufferedLength();
632 _headersWritten = true;
635 bufferedLength = _httpWriter.GetBufferedLength();
639 // Filter and recalculate length if not done already
642 if (!_filteringCompleted) {
643 _httpWriter.Filter(false);
644 bufferedLength = _httpWriter.GetBufferedLength();
651 // suppress HEAD content unless overriden
652 if (!_suppressContentSet && Request != null && Request.HttpVerb == HttpVerb.HEAD)
653 _suppressContent = true;
655 if (_suppressContent || _ended) {
656 _httpWriter.ClearBuffers();
660 if (!_clientDisconnected) {
661 // Fire pre-send request event
662 if (_context != null && _context.ApplicationInstance != null)
663 _context.ApplicationInstance.RaiseOnPreSendRequestContent();
666 if (bufferedLength > 0) {
667 byte[] chunkPrefix = Encoding.ASCII.GetBytes(Convert.ToString(bufferedLength, 16) + "\r\n");
668 _wr.SendResponseFromMemory(chunkPrefix, chunkPrefix.Length);
670 _httpWriter.Send(_wr);
672 _wr.SendResponseFromMemory(s_chunkSuffix, s_chunkSuffix.Length);
676 _wr.SendResponseFromMemory(s_chunkEnd, s_chunkEnd.Length);
679 _httpWriter.Send(_wr);
683 needToClearBuffers = !finalFlush;
684 _wr.FlushResponse(finalFlush);
686 _wr.UpdateResponseCounters(finalFlush, (int)bufferedLength);
692 // Remember if completed
693 if (finalFlush && _headersWritten)
696 // clear buffers even if FlushResponse throws
697 if (needToClearBuffers)
698 _httpWriter.ClearBuffers();
702 internal void FinalFlushAtTheEndOfRequestProcessing() {
703 FinalFlushAtTheEndOfRequestProcessing(false);
706 internal void FinalFlushAtTheEndOfRequestProcessing(bool needPipelineCompletion) {
710 // Returns true if the HttpWorkerRequest supports asynchronous flush; otherwise false.
711 public bool SupportsAsyncFlush {
713 return (_wr != null && _wr.SupportsAsyncFlush);
717 // Sends the currently buffered response to the client. If the underlying HttpWorkerRequest
718 // supports asynchronous flush and this method is called from an asynchronous module event
719 // or asynchronous handler, then the send will be performed asynchronously. Otherwise the
720 // implementation resorts to a synchronous flush. The HttpResponse.SupportsAsyncFlush property
721 // returns the value of HttpWorkerRequest.SupportsAsyncFlush. Asynchronous flush is supported
722 // for IIS 6.0 and higher.
723 public IAsyncResult BeginFlush(AsyncCallback callback, Object state) {
725 throw new HttpException(SR.GetString(SR.Cannot_flush_completed_response));
727 // perform async flush if it is supported
728 if (_wr != null && _wr.SupportsAsyncFlush && !_context.IsInCancellablePeriod) {
730 return _wr.BeginFlush(callback, state);
733 // perform a sync flush since async is not supported
734 FlushAsyncResult ar = new FlushAsyncResult(callback, state);
741 ar.Complete(0, HResults.S_OK, IntPtr.Zero, synchronous: true);
745 // Finish an asynchronous flush.
746 public void EndFlush(IAsyncResult asyncResult) {
747 // finish async flush if it is supported
748 if (_wr != null && _wr.SupportsAsyncFlush && !_context.IsInCancellablePeriod) {
749 // integrated mode doesn't set this until after ExplicitFlush is called,
750 // but classic mode sets it after WriteHeaders is called
751 _headersWritten = true;
752 if (!(_wr is IIS7WorkerRequest)) {
753 _httpWriter.ClearBuffers();
755 _wr.EndFlush(asyncResult);
759 // finish sync flush since async is not supported
760 if (asyncResult == null)
761 throw new ArgumentNullException("asyncResult");
762 FlushAsyncResult ar = asyncResult as FlushAsyncResult;
764 throw new ArgumentException(null, "asyncResult");
765 ar.ReleaseWaitHandleWhenSignaled();
766 if (ar.Error != null) {
771 public Task FlushAsync() {
772 return Task.Factory.FromAsync(BeginFlush, EndFlush, state: null);
775 // WOS 1555777: kernel cache support
776 // If the response can be kernel cached, return the kernel cache key;
777 // otherwise return null. The kernel cache key is used to invalidate
778 // the entry if a dependency changes or the item is flushed from the
779 // managed cache for any reason.
780 internal String SetupKernelCaching(String originalCacheUrl) {
781 // don't kernel cache if we have a cookie header
782 if (_cookies != null && _cookies.Count != 0) {
783 _cachePolicy.SetHasSetCookieHeader();
787 bool enableKernelCacheForVaryByStar = IsKernelCacheEnabledForVaryByStar();
789 // check cache policy
790 if (!_cachePolicy.IsKernelCacheable(Request, enableKernelCacheForVaryByStar)) {
794 // check configuration if the kernel mode cache is enabled
795 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetLKGConfig(_context).HttpRuntime;
796 if (runtimeConfig == null || !runtimeConfig.EnableKernelOutputCache) {
800 double seconds = (_cachePolicy.UtcGetAbsoluteExpiration() - DateTime.UtcNow).TotalSeconds;
805 int secondsToLive = seconds < Int32.MaxValue ? (int) seconds : Int32.MaxValue;
806 string kernelCacheUrl = _wr.SetupKernelCaching(secondsToLive, originalCacheUrl, enableKernelCacheForVaryByStar);
808 if (kernelCacheUrl != null) {
809 // Tell cache policy not to use max-age as kernel mode cache doesn't update it
810 _cachePolicy.SetNoMaxAgeInCacheControl();
813 return kernelCacheUrl;
817 * Disable kernel caching for this response. If kernel caching is not supported, this method
818 * returns without performing any action.
820 public void DisableKernelCache() {
825 _wr.DisableKernelCache();
829 * Disable IIS user-mode caching for this response. If IIS user-mode caching is not supported, this method
830 * returns without performing any action.
832 public void DisableUserCache() {
837 _wr.DisableUserCache();
840 private bool IsKernelCacheEnabledForVaryByStar()
842 OutputCacheSection outputCacheConfig = RuntimeConfig.GetAppConfig().OutputCache;
843 return (_cachePolicy.IsVaryByStar && outputCacheConfig.EnableKernelCacheForVaryByStar);
846 internal void FilterOutput() {
847 if(_filteringCompleted) {
852 if (UsingHttpWriter) {
853 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
854 if (iis7WorkerRequest != null) {
855 _httpWriter.FilterIntegrated(true, iis7WorkerRequest);
858 _httpWriter.Filter(true);
863 _filteringCompleted = true;
868 /// Prevents any other writes to the Response
870 internal void IgnoreFurtherWrites() {
871 if (UsingHttpWriter) {
872 _httpWriter.IgnoreFurtherWrites();
877 * Is the entire response buffered so far
879 internal bool IsBuffered() {
880 return !_headersWritten && UsingHttpWriter;
883 // Expose cookie collection to request
884 // Gets the HttpCookie collection sent by the current request.</para>
885 public HttpCookieCollection Cookies {
887 if (_cookies == null)
888 _cookies = new HttpCookieCollection(this, false);
894 // returns TRUE iff there is at least one response cookie marked Shareable = false
895 internal bool ContainsNonShareableCookies() {
896 if (_cookies != null) {
897 for (int i = 0; i < _cookies.Count; i++) {
898 if (!_cookies[i].Shareable) {
906 internal HttpCookieCollection GetCookiesNoCreate() {
910 public NameValueCollection Headers {
912 if ( !(_wr is IIS7WorkerRequest) ) {
913 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
916 if (_headers == null) {
917 _headers = new HttpHeaderCollection(_wr, this, 16);
925 * Add dependency on a file to the current response
929 /// <para>Adds dependency on a file to the current response.</para>
931 public void AddFileDependency(String filename) {
932 _fileDependencyList.AddDependency(filename, "filename");
935 // Add dependency on a list of files to the current response
937 // Adds dependency on a group of files to the current response.
938 public void AddFileDependencies(ArrayList filenames) {
939 _fileDependencyList.AddDependencies(filenames, "filenames");
943 public void AddFileDependencies(string[] filenames) {
944 _fileDependencyList.AddDependencies(filenames, "filenames");
947 internal void AddVirtualPathDependencies(string[] virtualPaths) {
948 _virtualPathDependencyList.AddDependencies(virtualPaths, "virtualPaths", false, Request.Path);
951 internal void AddFileDependencies(string[] filenames, DateTime utcTime) {
952 _fileDependencyList.AddDependencies(filenames, "filenames", false, utcTime);
955 // Add dependency on another cache item to the response.
956 public void AddCacheItemDependency(string cacheKey) {
957 _cacheItemDependencyList.AddDependency(cacheKey, "cacheKey");
960 // Add dependency on a list of cache items to the response.
961 public void AddCacheItemDependencies(ArrayList cacheKeys) {
962 _cacheItemDependencyList.AddDependencies(cacheKeys, "cacheKeys");
966 public void AddCacheItemDependencies(string[] cacheKeys) {
967 _cacheItemDependencyList.AddDependencies(cacheKeys, "cacheKeys");
970 // Add dependency on one or more CacheDependency objects to the response
971 public void AddCacheDependency(params CacheDependency[] dependencies) {
972 if (dependencies == null) {
973 throw new ArgumentNullException("dependencies");
975 if (dependencies.Length == 0) {
978 if (_cacheDependencyForResponse != null) {
979 throw new InvalidOperationException(SR.GetString(SR.Invalid_operation_cache_dependency));
981 if (_userAddedDependencies == null) {
982 // copy array argument contents so they can't be changed beneath us
983 _userAddedDependencies = (CacheDependency[]) dependencies.Clone();
986 CacheDependency[] deps = new CacheDependency[_userAddedDependencies.Length + dependencies.Length];
988 for (i = 0; i < _userAddedDependencies.Length; i++) {
989 deps[i] = _userAddedDependencies[i];
991 for (int j = 0; j < dependencies.Length; j++) {
992 deps[i + j] = dependencies[j];
994 _userAddedDependencies = deps;
996 Cache.SetDependencies(true);
999 public static void RemoveOutputCacheItem(string path) {
1000 RemoveOutputCacheItem(path, null);
1003 public static void RemoveOutputCacheItem(string path, string providerName) {
1005 throw new ArgumentNullException("path");
1006 if (StringUtil.StringStartsWith(path, "\\\\") || path.IndexOf(':') >= 0 || !UrlPath.IsRooted(path))
1007 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_remove, path));
1009 string key = OutputCacheModule.CreateOutputCachedItemKey(
1010 path, HttpVerb.GET, null, null);
1012 if (providerName == null) {
1013 OutputCache.Remove(key, (HttpContext)null);
1016 OutputCache.RemoveFromProvider(key, providerName);
1019 key = OutputCacheModule.CreateOutputCachedItemKey(
1020 path, HttpVerb.POST, null, null);
1022 if (providerName == null) {
1023 OutputCache.Remove(key, (HttpContext)null);
1026 OutputCache.RemoveFromProvider(key, providerName);
1030 // Check if there are file dependencies.
1031 internal bool HasFileDependencies() {
1032 return _fileDependencyList.HasDependencies();
1035 // Check if there are item dependencies.
1036 internal bool HasCacheItemDependencies() {
1037 return _cacheItemDependencyList.HasDependencies();
1040 internal CacheDependency CreateCacheDependencyForResponse() {
1041 if (_cacheDependencyForResponse == null) {
1042 CacheDependency dependency;
1044 // N.B. - add file dependencies last so that we hit the file changes monitor
1046 dependency = _cacheItemDependencyList.CreateCacheDependency(CacheDependencyType.CacheItems, null);
1047 dependency = _fileDependencyList.CreateCacheDependency(CacheDependencyType.Files, dependency);
1048 dependency = _virtualPathDependencyList.CreateCacheDependency(CacheDependencyType.VirtualPaths, dependency);
1050 // N.B. we add in the aggregate dependency here, and return it,
1051 // so this function should only be called once, because the resulting
1052 // dependency can only be added to the cache once
1053 if (_userAddedDependencies != null) {
1054 AggregateCacheDependency agg = new AggregateCacheDependency();
1055 agg.Add(_userAddedDependencies);
1056 if (dependency != null) {
1057 agg.Add(dependency);
1059 // clear it because we added them to the dependencies for the response
1060 _userAddedDependencies = null;
1061 _cacheDependencyForResponse = agg;
1064 _cacheDependencyForResponse = dependency;
1067 return _cacheDependencyForResponse;
1070 // Get response headers and content as HttpRawResponse
1071 internal HttpRawResponse GetSnapshot() {
1072 int statusCode = 200;
1073 string statusDescription = null;
1074 ArrayList headers = null;
1075 ArrayList buffers = null;
1076 bool hasSubstBlocks = false;
1079 throw new HttpException(SR.GetString(SR.Cannot_get_snapshot_if_not_buffered));
1081 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
1084 if (!_suppressContent) {
1085 if (iis7WorkerRequest != null) {
1086 buffers = _httpWriter.GetIntegratedSnapshot(out hasSubstBlocks, iis7WorkerRequest);
1089 buffers = _httpWriter.GetSnapshot(out hasSubstBlocks);
1093 // headers (after data as the data has side effects (like charset, see ASURT 113202))
1094 if (!_suppressHeaders) {
1095 statusCode = _statusCode;
1096 statusDescription = _statusDescription;
1097 // In integrated pipeline, we need to use the current response headers
1098 // from the response (these may have been generated by other handlers, etc)
1099 // instead of the ASP.NET cached headers
1100 if (iis7WorkerRequest != null) {
1101 headers = GenerateResponseHeadersIntegrated(true);
1104 headers = GenerateResponseHeaders(true);
1107 return new HttpRawResponse(statusCode, statusDescription, headers, buffers, hasSubstBlocks);
1110 // Send saved response snapshot as the entire response
1111 internal void UseSnapshot(HttpRawResponse rawResponse, bool sendBody) {
1112 if (_headersWritten)
1113 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_after_headers_sent));
1115 if (_httpWriter == null)
1116 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter));
1121 StatusCode = rawResponse.StatusCode;
1122 StatusDescription = rawResponse.StatusDescription;
1125 ArrayList headers = rawResponse.Headers;
1126 int n = (headers != null) ? headers.Count : 0;
1127 for (int i = 0; i < n; i++) {
1128 HttpResponseHeader h = (HttpResponseHeader)(headers[i]);
1129 this.AppendHeader(h.Name, h.Value);
1133 SetResponseBuffers(rawResponse.Buffers);
1135 _suppressContent = !sendBody;
1138 // set the response content bufffers
1139 internal void SetResponseBuffers(ArrayList buffers) {
1140 if (_httpWriter == null) {
1141 throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter));
1144 _httpWriter.UseSnapshot(buffers);
1147 internal void CloseConnectionAfterError() {
1148 _closeConnectionAfterError = true;
1151 private void WriteErrorMessage(Exception e, bool dontShowSensitiveErrors) {
1152 ErrorFormatter errorFormatter = null;
1153 CultureInfo uiculture = null, savedUiculture = null;
1154 bool needToRestoreUiculture = false;
1156 if (_context.DynamicUICulture != null) {
1157 // if the user set the culture dynamically use it
1158 uiculture = _context.DynamicUICulture;
1161 // get the UI culture under which the error text must be created (use LKG to avoid errors while reporting error)
1162 GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1163 if ((globConfig != null) && (!String.IsNullOrEmpty(globConfig.UICulture))) {
1165 uiculture = HttpServerUtility.CreateReadOnlyCultureInfo(globConfig.UICulture);
1172 // In Integrated mode, generate the necessary response headers for the error
1173 GenerateResponseHeadersForHandler();
1175 // set the UI culture
1176 if (uiculture != null) {
1177 savedUiculture = Thread.CurrentThread.CurrentUICulture;
1178 Thread.CurrentThread.CurrentUICulture = uiculture;
1179 needToRestoreUiculture = true;
1184 // Try to get an error formatter
1185 errorFormatter = GetErrorFormatter(e);
1187 Debug.Trace("internal", "Error stack for " + Request.Path, e);
1189 if (dontShowSensitiveErrors && !errorFormatter.CanBeShownToAllUsers)
1190 errorFormatter = new GenericApplicationErrorFormatter(Request.IsLocal);
1192 Debug.Trace("internal", "errorFormatter's type = " + errorFormatter.GetType());
1194 if (ErrorFormatter.RequiresAdaptiveErrorReporting(Context)) {
1195 _writer.Write(errorFormatter.GetAdaptiveErrorMessage(Context, dontShowSensitiveErrors));
1198 _writer.Write(errorFormatter.GetHtmlErrorMessage(dontShowSensitiveErrors));
1200 // Write a stack dump in an HTML comment for debugging purposes
1201 // Only show it for Asp permission medium or higher (ASURT 126373)
1202 if (!dontShowSensitiveErrors &&
1203 HttpRuntime.HasAspNetHostingPermission(AspNetHostingPermissionLevel.Medium)) {
1204 _writer.Write("<!-- \r\n");
1205 WriteExceptionStack(e);
1206 _writer.Write("-->");
1208 if (!dontShowSensitiveErrors && !Request.IsLocal ) {
1209 _writer.Write("<!-- \r\n");
1210 _writer.Write(SR.GetString(SR.Information_Disclosure_Warning));
1211 _writer.Write("-->");
1215 if (_closeConnectionAfterError) {
1221 // restore ui culture
1222 if (needToRestoreUiculture)
1223 Thread.CurrentThread.CurrentUICulture = savedUiculture;
1226 catch { // Protect against exception filters
1231 internal void SetOverrideErrorFormatter(ErrorFormatter errorFormatter) {
1232 _overrideErrorFormatter = errorFormatter;
1235 internal ErrorFormatter GetErrorFormatter(Exception e) {
1236 ErrorFormatter errorFormatter = null;
1238 if (_overrideErrorFormatter != null) {
1239 return _overrideErrorFormatter;
1242 // Try to get an error formatter
1243 errorFormatter = HttpException.GetErrorFormatter(e);
1245 if (errorFormatter == null) {
1246 ConfigurationException ce = e as ConfigurationException;
1247 if (ce != null && !String.IsNullOrEmpty(ce.Filename))
1248 errorFormatter = new ConfigErrorFormatter(ce);
1251 // If we couldn't get one, create one here
1252 if (errorFormatter == null) {
1253 // If it's a 404, use a special error page, otherwise, use a more
1255 if (_statusCode == 404)
1256 errorFormatter = new PageNotFoundErrorFormatter(Request.Path);
1257 else if (_statusCode == 403)
1258 errorFormatter = new PageForbiddenErrorFormatter(Request.Path);
1260 if (e is System.Security.SecurityException)
1261 errorFormatter = new SecurityErrorFormatter(e);
1263 errorFormatter = new UnhandledErrorFormatter(e);
1267 // Show config source only on local request for security reasons
1268 // Config file snippet may unintentionally reveal sensitive information (not related to the error)
1269 ConfigErrorFormatter configErrorFormatter = errorFormatter as ConfigErrorFormatter;
1270 if (configErrorFormatter != null) {
1271 configErrorFormatter.AllowSourceCode = Request.IsLocal;
1274 return errorFormatter;
1277 private void WriteOneExceptionStack(Exception e) {
1278 Exception subExcep = e.InnerException;
1279 if (subExcep != null)
1280 WriteOneExceptionStack(subExcep);
1282 string title = "[" + e.GetType().Name + "]";
1283 if (e.Message != null && e.Message.Length > 0)
1284 title += ": " + HttpUtility.HtmlEncode(e.Message);
1286 _writer.WriteLine(title);
1287 if (e.StackTrace != null)
1288 _writer.WriteLine(e.StackTrace);
1291 private void WriteExceptionStack(Exception e) {
1292 ConfigurationErrorsException errors = e as ConfigurationErrorsException;
1293 if (errors == null) {
1294 WriteOneExceptionStack(e);
1297 // Write the original exception to get the first error with
1298 // a full stack trace
1299 WriteOneExceptionStack(e);
1301 // Write additional errors, which will contain truncated stacks
1302 ICollection col = errors.Errors;
1303 if (col.Count > 1) {
1304 bool firstSkipped = false;
1305 foreach (ConfigurationException ce in col) {
1306 if (!firstSkipped) {
1307 firstSkipped = true;
1311 _writer.WriteLine("---");
1312 WriteOneExceptionStack(ce);
1318 internal void ReportRuntimeError(Exception e, bool canThrow, bool localExecute) {
1319 CustomErrorsSection customErrorsSetting = null;
1320 bool useCustomErrors = false;
1326 // always try to disable IIS custom errors when we send an error
1328 _wr.TrySkipIisCustomErrors = true;
1331 if (!localExecute) {
1332 code = HttpException.GetHttpCodeForException(e);
1334 // Don't raise event for 404. See VSWhidbey 124147.
1336 WebBaseEvent.RaiseRuntimeError(e, this);
1339 // This cannot use the HttpContext.IsCustomErrorEnabled property, since it must call
1340 // GetSettings() with the canThrow parameter.
1341 customErrorsSetting = CustomErrorsSection.GetSettings(_context, canThrow);
1342 if (customErrorsSetting != null)
1343 useCustomErrors = customErrorsSetting.CustomErrorsEnabled(Request);
1345 useCustomErrors = true;
1348 if (!_headersWritten) {
1349 // nothing sent yet - entire response
1352 code = HttpException.GetHttpCodeForException(e);
1355 // change 401 to 500 in case the config is not to impersonate
1356 if (code == 401 && !_context.IsClientImpersonationConfigured)
1359 if (_context.TraceIsEnabled)
1360 _context.Trace.StatusCode = code;
1362 if (!localExecute && useCustomErrors) {
1363 String redirect = (customErrorsSetting != null) ? customErrorsSetting.GetRedirectString(code) : null;
1365 RedirectToErrorPageStatus redirectStatus = RedirectToErrorPage(redirect, customErrorsSetting.RedirectMode);
1366 switch (redirectStatus) {
1367 case RedirectToErrorPageStatus.Success:
1368 // success - nothing to do
1371 case RedirectToErrorPageStatus.NotAttempted:
1372 // if no redirect display generic error
1375 WriteErrorMessage(e, dontShowSensitiveErrors: true);
1379 // DevDiv #70492 - If we tried to display the custom error page but failed in doing so, we should display
1380 // a generic error message instead of trying to display the original error. We have a compat switch on
1381 // the <customErrors> element to control this behavior.
1383 if (customErrorsSetting.AllowNestedErrors) {
1384 // The user has set the compat switch to use the original (pre-bug fix) behavior.
1385 goto case RedirectToErrorPageStatus.NotAttempted;
1390 HttpException dummyException = new HttpException();
1391 dummyException.SetFormatter(new CustomErrorFailedErrorFormatter());
1392 WriteErrorMessage(dummyException, dontShowSensitiveErrors: true);
1399 WriteErrorMessage(e, dontShowSensitiveErrors: false);
1405 if (_contentType != null && _contentType.Equals("text/html")) {
1406 // in the middle of Html - break Html
1407 Write("\r\n\r\n</pre></table></table></table></table></table>");
1408 Write("</font></font></font></font></font>");
1409 Write("</i></i></i></i></i></b></b></b></b></b></u></u></u></u></u>");
1410 Write("<p> </p><hr>\r\n\r\n");
1413 WriteErrorMessage(e, useCustomErrors);
1417 internal void SynchronizeStatus(int statusCode, int subStatusCode, string description) {
1418 _statusCode = statusCode;
1419 _subStatusCode = subStatusCode;
1420 _statusDescription = description;
1424 internal void SynchronizeHeader(int knownHeaderIndex, string name, string value) {
1425 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
1426 headers.SynchronizeHeader(name, value);
1428 // unknown headers have an index < 0
1429 if (knownHeaderIndex < 0) {
1433 bool fHeadersWritten = HeadersWritten;
1434 HeadersWritten = false; // Turn off the warning for "Headers have been written and can not be set"
1436 switch (knownHeaderIndex) {
1437 case HttpWorkerRequest.HeaderCacheControl:
1438 _cacheControlHeaderAdded = true;
1440 case HttpWorkerRequest.HeaderContentType:
1441 _contentType = value;
1443 case HttpWorkerRequest.HeaderLocation:
1444 _redirectLocation = value;
1445 _redirectLocationSet = false;
1447 case HttpWorkerRequest.HeaderSetCookie:
1448 // If the header is Set-Cookie, update the corresponding
1449 // cookie in the cookies collection
1450 if (value != null) {
1451 HttpCookie cookie = HttpRequest.CreateCookieFromString(value);
1452 // do not write this cookie back to IIS
1453 cookie.IsInResponseHeader = true;
1454 Cookies.Set(cookie);
1455 cookie.Changed = false;
1456 cookie.Added = false;
1461 HeadersWritten = fHeadersWritten;
1465 internal void SyncStatusIntegrated() {
1466 Debug.Assert(_wr is IIS7WorkerRequest, "_wr is IIS7WorkerRequest");
1467 if (!_headersWritten && _statusSet) {
1468 // For integrated pipeline, synchronize the status immediately so that the FREB log
1469 // correctly indicates the module and notification that changed the status.
1470 _wr.SendStatus(_statusCode, _subStatusCode, this.StatusDescription);
1475 // Public properties
1478 // Gets or sets the HTTP status code of output returned to client.
1479 public int StatusCode {
1485 if (_headersWritten)
1486 throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1488 if (_statusCode != value) {
1489 _statusCode = value;
1491 _statusDescription = null;
1497 // the IIS sub status code
1498 // since this doesn't get emitted in the protocol
1499 // we won't send it through the worker request interface
1501 public int SubStatusCode {
1503 if ( !(_wr is IIS7WorkerRequest) ) {
1504 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1507 return _subStatusCode;
1510 if ( !(_wr is IIS7WorkerRequest) ) {
1511 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
1514 if (_headersWritten) {
1515 throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1518 _subStatusCode = value;
1523 // Allows setting both the status and the substatus individually. If not in IIS7 integrated mode,
1524 // the substatus code is ignored so as not to throw an exception.
1525 internal void SetStatusCode(int statusCode, int subStatus = -1) {
1526 StatusCode = statusCode;
1527 if (subStatus >= 0 && _wr is IIS7WorkerRequest) {
1528 SubStatusCode = subStatus;
1533 * Http status description string
1536 // Http status description string
1537 // Gets or sets the HTTP status string of output returned to the client.
1538 public String StatusDescription {
1540 if (_statusDescription == null)
1541 _statusDescription = HttpWorkerRequest.GetStatusDescription(_statusCode);
1543 return _statusDescription;
1547 if (_headersWritten)
1548 throw new HttpException(SR.GetString(SR.Cannot_set_status_after_headers_sent));
1550 if (value != null && value.Length > 512) // ASURT 124743
1551 throw new ArgumentOutOfRangeException("value");
1552 _statusDescription = value;
1557 public bool TrySkipIisCustomErrors {
1560 return _wr.TrySkipIisCustomErrors;
1566 _wr.TrySkipIisCustomErrors = value;
1572 /// By default, the FormsAuthenticationModule hooks EndRequest and converts HTTP 401 status codes to
1573 /// HTTP 302, redirecting to the login page. This isn't appropriate for certain classes of errors,
1574 /// e.g. where authentication succeeded but authorization failed, or where the current request is
1575 /// an AJAX or web service request. This property provides a way to suppress the redirect behavior
1576 /// and send the original status code to the client.
1578 public bool SuppressFormsAuthenticationRedirect {
1584 /// By default, ASP.NET sends a "Cache-Control: private" response header unless an explicit cache
1585 /// policy has been specified for this response. This property allows suppressing this default
1586 /// response header on a per-request basis. It can still be suppressed for the entire application
1587 /// by setting the appropriate value in <httpRuntime> or <outputCache>. See
1588 /// http://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.sendcachecontrolheader.aspx
1589 /// for more information on those config elements.
1592 /// Developers should use caution when suppressing the default Cache-Control header, as proxies
1593 /// and other intermediaries may treat responses without this header as cacheable by default.
1594 /// This could lead to the inadvertent caching of sensitive information.
1595 /// See RFC 2616, Sec. 13.4, for more information.
1597 public bool SuppressDefaultCacheControlHeader {
1602 // Flag indicating to buffer the output
1603 // Gets or sets a value indicating whether HTTP output is buffered.
1604 public bool BufferOutput {
1606 return _bufferOutput;
1610 if (_bufferOutput != value) {
1611 _bufferOutput = value;
1613 if (_httpWriter != null)
1614 _httpWriter.UpdateResponseBuffering();
1619 // Gets the Content-Encoding HTTP response header.
1620 internal String GetHttpHeaderContentEncoding() {
1621 string coding = null;
1622 if (_wr is IIS7WorkerRequest) {
1623 if (_headers != null) {
1624 coding = _headers["Content-Encoding"];
1627 else if (_customHeaders != null) {
1628 int numCustomHeaders = _customHeaders.Count;
1629 for (int i = 0; i < numCustomHeaders; i++) {
1630 HttpResponseHeader h = (HttpResponseHeader)_customHeaders[i];
1631 if (h.Name == "Content-Encoding") {
1645 /// <para>Gets or sets the
1646 /// HTTP MIME type of output.</para>
1648 public String ContentType {
1650 return _contentType;
1654 if (_headersWritten) {
1655 // Don't throw if the new content type is the same as the current one
1656 if (_contentType == value)
1659 throw new HttpException(SR.GetString(SR.Cannot_set_content_type_after_headers_sent));
1662 _contentTypeSetByManagedCaller = true;
1663 _contentType = value;
1668 // Gets or sets the HTTP charset of output.
1669 public String Charset {
1671 if (_charSet == null)
1672 _charSet = ContentEncoding.WebName;
1678 if (_headersWritten)
1679 throw new HttpException(SR.GetString(SR.Cannot_set_content_type_after_headers_sent));
1684 _charSet = String.Empty; // to differentiate between not set (default) and empty chatset
1686 _customCharSet = true;
1690 // Content encoding for conversion
1691 // Gets or sets the HTTP character set of output.
1692 public Encoding ContentEncoding {
1694 if (_encoding == null) {
1695 // use LKG config because Response.ContentEncoding is need to display [config] error
1696 GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1697 if (globConfig != null)
1698 _encoding = globConfig.ResponseEncoding;
1700 if (_encoding == null)
1701 _encoding = Encoding.Default;
1709 throw new ArgumentNullException("value");
1711 if (_encoding == null || !_encoding.Equals(value)) {
1713 _encoder = null; // flush cached encoder
1715 if (_httpWriter != null)
1716 _httpWriter.UpdateResponseEncoding();
1722 public Encoding HeaderEncoding {
1724 if (_headerEncoding == null) {
1725 // use LKG config because Response.ContentEncoding is need to display [config] error
1726 GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1727 if (globConfig != null)
1728 _headerEncoding = globConfig.ResponseHeaderEncoding;
1730 // default to UTF-8 (also for Unicode as headers cannot be double byte encoded)
1731 if (_headerEncoding == null || _headerEncoding.Equals(Encoding.Unicode))
1732 _headerEncoding = Encoding.UTF8;
1735 return _headerEncoding;
1740 throw new ArgumentNullException("value");
1742 if (value.Equals(Encoding.Unicode)) {
1743 throw new HttpException(SR.GetString(SR.Invalid_header_encoding, value.WebName));
1746 if (_headerEncoding == null || !_headerEncoding.Equals(value)) {
1747 if (_headersWritten)
1748 throw new HttpException(SR.GetString(SR.Cannot_set_header_encoding_after_headers_sent));
1750 _headerEncoding = value;
1755 // Encoder cached for the current encoding
1756 internal Encoder ContentEncoder {
1758 if (_encoder == null) {
1759 Encoding e = ContentEncoding;
1760 _encoder = e.GetEncoder();
1762 // enable best fit mapping accoding to config
1763 // (doesn't apply to utf-8 which is the default, thus optimization)
1765 if (!e.Equals(Encoding.UTF8)) {
1766 bool enableBestFit = false;
1768 GlobalizationSection globConfig = RuntimeConfig.GetLKGConfig(_context).Globalization;
1769 if (globConfig != null) {
1770 enableBestFit = globConfig.EnableBestFitResponseEncoding;
1773 if (!enableBestFit) {
1774 // setting 'fallback' disables best fit mapping
1775 _encoder.Fallback = new EncoderReplacementFallback();
1784 // Returns the caching semantics of the Web page (expiration time, privacy, vary clauses).
1785 public HttpCachePolicy Cache {
1787 if (_cachePolicy == null) {
1788 _cachePolicy = new HttpCachePolicy();
1791 return _cachePolicy;
1795 // Return whether or not we have cache policy. We don't want to create it in
1796 // situations where we don't modify it.
1797 internal bool HasCachePolicy {
1799 return _cachePolicy != null;
1803 // Client connected flag
1804 // Gets a value indicating whether the client is still connected to the server.
1805 public bool IsClientConnected {
1807 if (_clientDisconnected)
1810 if (_wr != null && !_wr.IsClientConnected()) {
1811 _clientDisconnected = true;
1820 /// Returns a CancellationToken that is tripped when the client disconnects. This can be used
1821 /// to listen for async disconnect notifications.
1824 /// This method requires that the application be hosted on IIS 7.5 or higher and that the
1825 /// application pool be running the integrated mode pipeline.
1827 /// Consumers should be aware of some restrictions when consuming this CancellationToken.
1828 /// Failure to heed these warnings can lead to race conditions, deadlocks, or other
1829 /// undefined behavior.
1831 /// - This API is thread-safe. However, ASP.NET will dispose of the token object at the
1832 /// end of the request. Consumers should exercise caution and ensure that they're not
1833 /// calling into this API outside the bounds of a single request. This is similar to
1834 /// the contract with BCL Task-returning methods which take a CancellationToken as a
1835 /// parameter: the callee should not touch the CancellationToken after the returned
1836 /// Task transitions to a terminal state.
1838 /// - DO NOT wait on the CancellationToken.WaitHandle, as this defeats the purpose of an
1839 /// async notification and can cause deadlocks.
1841 /// - DO NOT call the CancellationToken.Register overloads which invoke the callback on
1842 /// the original SynchronizationContext.
1844 /// - DO NOT consume HttpContext or other non-thread-safe ASP.NET intrinsic objects from
1845 /// within the callback provided to Register. Remember: the callback may be running
1846 /// concurrently with other ASP.NET or application code.
1848 /// - DO keep the callback methods short-running and non-blocking. Make every effort to
1849 /// avoid throwing exceptions from within the callback methods.
1851 /// - We do not guarantee that we will ever transition the token to a canceled state.
1852 /// For example, if the request finishes without the client having disconnected, we
1853 /// will dispose of this token as mentioned earlier without having first canceled it.
1855 public CancellationToken ClientDisconnectedToken {
1857 IIS7WorkerRequest wr = _wr as IIS7WorkerRequest;
1858 CancellationToken cancellationToken;
1859 if (wr != null && wr.TryGetClientDisconnectedCancellationToken(out cancellationToken)) {
1860 return cancellationToken;
1863 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_75_Integrated));
1868 public bool IsRequestBeingRedirected {
1870 return _isRequestBeingRedirected;
1873 _isRequestBeingRedirected = value;
1879 /// <para>Gets or Sets a redirection string (value of location resposne header) for redirect response.</para>
1881 public String RedirectLocation {
1882 get { return _redirectLocation; }
1884 if (_headersWritten)
1885 throw new HttpException(SR.GetString(SR.Cannot_append_header_after_headers_sent));
1887 _redirectLocation = value;
1888 _redirectLocationSet = true;
1897 /// <para>Closes the socket connection to a client.</para>
1899 public void Close() {
1900 if (!_clientDisconnected && !_completed && _wr != null) {
1901 _wr.CloseConnection();
1902 _clientDisconnected = true;
1906 // TextWriter object
1907 // Enables custom output to the outgoing Http content body.
1908 public TextWriter Output {
1909 get { return _writer;}
1910 set { _writer = value; }
1913 internal TextWriter SwitchWriter(TextWriter writer) {
1914 TextWriter oldWriter = _writer;
1920 // Enables binary output to the outgoing Http content body.
1921 public Stream OutputStream {
1923 if (!UsingHttpWriter)
1924 throw new HttpException(SR.GetString(SR.OutputStream_NotAvail));
1926 return _httpWriter.OutputStream;
1930 // ASP classic compat
1931 // Writes a string of binary characters to the HTTP output stream.
1932 public void BinaryWrite(byte[] buffer) {
1933 OutputStream.Write(buffer, 0, buffer.Length);
1937 // Appends a PICS (Platform for Internet Content Selection) label HTTP header to the output stream.
1938 public void Pics(String value) {
1939 AppendHeader("PICS-Label", value);
1943 // Specifies a wrapping filter object to modify HTTP entity body before transmission.
1944 public Stream Filter {
1946 if (UsingHttpWriter)
1947 return _httpWriter.GetCurrentFilter();
1953 if (UsingHttpWriter) {
1954 _httpWriter.InstallFilter(value);
1956 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
1957 if (iis7WorkerRequest != null) {
1958 iis7WorkerRequest.ResponseFilterInstalled();
1962 throw new HttpException(SR.GetString(SR.Filtering_not_allowed));
1967 // Flag to suppress writing of content
1968 // Gets or sets a value indicating that HTTP content will not be sent to client.
1969 public bool SuppressContent {
1971 return _suppressContent;
1975 _suppressContent = value;
1976 _suppressContentSet = true;
1985 * Add Http custom header
1987 * @param name header name
1988 * @param value header value
1992 /// <para>Adds an HTTP
1993 /// header to the output stream.</para>
1995 public void AppendHeader(String name, String value) {
1996 bool isCacheHeader = false;
1998 if (_headersWritten)
1999 throw new HttpException(SR.GetString(SR.Cannot_append_header_after_headers_sent));
2001 // some headers are stored separately or require special action
2002 int knownHeaderIndex = HttpWorkerRequest.GetKnownResponseHeaderIndex(name);
2004 switch (knownHeaderIndex) {
2005 case HttpWorkerRequest.HeaderContentType:
2006 ContentType = value;
2007 return; // don't keep as custom header
2009 case HttpWorkerRequest.HeaderContentLength:
2010 _contentLengthSet = true;
2013 case HttpWorkerRequest.HeaderLocation:
2014 RedirectLocation = value;
2015 return; // don't keep as custom header
2017 case HttpWorkerRequest.HeaderTransferEncoding:
2018 _transferEncodingSet = true;
2021 case HttpWorkerRequest.HeaderCacheControl:
2022 _cacheControlHeaderAdded = true;
2023 goto case HttpWorkerRequest.HeaderExpires;
2024 case HttpWorkerRequest.HeaderExpires:
2025 case HttpWorkerRequest.HeaderLastModified:
2026 case HttpWorkerRequest.HeaderEtag:
2027 case HttpWorkerRequest.HeaderVary:
2028 isCacheHeader = true;
2032 // In integrated mode, write the headers directly
2033 if (_wr is IIS7WorkerRequest) {
2034 Headers.Add(name, value);
2039 // don't keep as custom header
2040 if (_cacheHeaders == null) {
2041 _cacheHeaders = new ArrayList();
2044 _cacheHeaders.Add(new HttpResponseHeader(knownHeaderIndex, value));
2048 HttpResponseHeader h;
2049 if (knownHeaderIndex >= 0)
2050 h = new HttpResponseHeader(knownHeaderIndex, value);
2052 h = new HttpResponseHeader(name, value);
2064 /// cookie to the output stream.
2067 public void AppendCookie(HttpCookie cookie) {
2068 if (_headersWritten)
2069 throw new HttpException(SR.GetString(SR.Cannot_append_cookie_after_headers_sent));
2071 Cookies.AddCookie(cookie, true);
2072 OnCookieAdd(cookie);
2079 public void SetCookie(HttpCookie cookie) {
2080 if (_headersWritten)
2081 throw new HttpException(SR.GetString(SR.Cannot_append_cookie_after_headers_sent));
2083 Cookies.AddCookie(cookie, false);
2084 OnCookieCollectionChange();
2087 internal void BeforeCookieCollectionChange() {
2088 if (_headersWritten)
2089 throw new HttpException(SR.GetString(SR.Cannot_modify_cookies_after_headers_sent));
2092 internal void OnCookieAdd(HttpCookie cookie) {
2093 // add to request's cookies as well
2094 Request.AddResponseCookie(cookie);
2097 internal void OnCookieCollectionChange() {
2098 // synchronize with request cookie collection
2099 Request.ResetCookies();
2102 // Clear response headers
2103 // Clears all headers from the buffer stream.
2104 public void ClearHeaders() {
2105 if (_headersWritten)
2106 throw new HttpException(SR.GetString(SR.Cannot_clear_headers_after_headers_sent));
2110 _statusDescription = null;
2112 _contentType = "text/html";
2113 _contentTypeSetByManagedCaller = false;
2115 _customCharSet = false;
2116 _contentLengthSet = false;
2118 _redirectLocation = null;
2119 _redirectLocationSet = false;
2120 _isRequestBeingRedirected = false;
2122 _customHeaders = null;
2124 if (_headers != null) {
2125 _headers.ClearInternal();
2128 _transferEncodingSet = false;
2131 if (_cookies != null) {
2133 Request.ResetCookies();
2136 if (_cachePolicy != null) {
2137 _cachePolicy.Reset();
2140 _cacheControlHeaderAdded = false;
2141 _cacheHeaders = null;
2143 _suppressHeaders = false;
2144 _suppressContent = false;
2145 _suppressContentSet = false;
2147 _expiresInMinutes = 0;
2148 _expiresInMinutesSet = false;
2149 _expiresAbsolute = DateTime.MinValue;
2150 _expiresAbsoluteSet = false;
2151 _cacheControl = null;
2153 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
2154 if (iis7WorkerRequest != null) {
2155 // clear the native response as well
2156 ClearNativeResponse(false, true, iis7WorkerRequest);
2158 // We need to regenerate Cache-Control: private only when the handler is managed and
2159 // configuration has <outputCache sendCacheControlHeader="true" /> in system.web
2161 if (_handlerHeadersGenerated && _sendCacheControlHeader) {
2162 Headers.Set("Cache-Control", "private");
2164 _handlerHeadersGenerated = false;
2170 /// <para>Clears all content output from the buffer stream.</para>
2172 public void ClearContent() {
2177 * Clear response buffer and headers. (For ASP compat doesn't clear headers)
2181 /// <para>Clears all headers and content output from the buffer stream.</para>
2183 public void Clear() {
2184 if (UsingHttpWriter)
2185 _httpWriter.ClearBuffers();
2187 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
2188 if (iis7WorkerRequest != null) {
2189 // clear the native response buffers too
2190 ClearNativeResponse(true, false, iis7WorkerRequest);
2197 * Clear response buffer and headers. Internal. Used to be 'Clear'.
2199 internal void ClearAll() {
2200 if (!_headersWritten)
2206 * Flush response currently buffered
2210 /// <para>Sends all currently buffered output to the client.</para>
2212 public void Flush() {
2214 throw new HttpException(SR.GetString(SR.Cannot_flush_completed_response));
2219 // Registers a callback that the ASP.NET runtime will invoke immediately before
2220 // response headers are sent for this request. This differs from the IHttpModule-
2221 // level pipeline event in that this is a per-request subscription rather than
2222 // a per-application subscription. The intent is that the callback may modify
2223 // the response status code or may set a response cookie or header. Other usage
2224 // notes and caveats:
2226 // - This API is available only in the IIS integrated mode pipeline and only
2227 // if response headers haven't yet been sent for this request.
2228 // - The ASP.NET runtime does not guarantee anything about the thread that the
2229 // callback is invoked on. For example, the callback may be invoked synchronously
2230 // on a background thread if a background flush is being performed.
2231 // HttpContext.Current is not guaranteed to be available on such a thread.
2232 // - The callback must not call any API that manipulates the response entity body
2233 // or that results in a flush. For example, the callback must not call
2234 // Response.Redirect, as that method may manipulate the response entity body.
2235 // - The callback must contain only short-running synchronous code. Trying to kick
2236 // off an asynchronous operation or wait on such an operation could result in
2238 // - The callback must not throw, otherwise behavior is undefined.
2239 [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = @"The normal event pattern doesn't work between HttpResponse and HttpResponseBase since the signatures differ.")]
2240 public ISubscriptionToken AddOnSendingHeaders(Action<HttpContext> callback) {
2241 if (callback == null) {
2242 throw new ArgumentNullException("callback");
2245 if (!(_wr is IIS7WorkerRequest)) {
2246 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
2249 if (HeadersWritten) {
2250 throw new HttpException(SR.GetString(SR.Cannot_call_method_after_headers_sent_generic));
2253 return _onSendingHeadersSubscriptionQueue.Enqueue(callback);
2257 * Append string to the log record
2259 * @param param string to append to the log record
2263 /// <para>Adds custom log information to the IIS log file.</para>
2265 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]
2266 public void AppendToLog(String param) {
2267 // only makes sense for IIS
2268 if (_wr is System.Web.Hosting.ISAPIWorkerRequest)
2269 ((System.Web.Hosting.ISAPIWorkerRequest)_wr).AppendLogParameter(param);
2270 else if (_wr is System.Web.Hosting.IIS7WorkerRequest)
2271 _context.Request.AppendToLogQueryString(param);
2276 /// <para>Redirects a client to a new URL.</para>
2278 public void Redirect(String url) {
2279 Redirect(url, true, false);
2283 /// <para>Redirects a client to a new URL.</para>
2285 public void Redirect(String url, bool endResponse) {
2286 Redirect(url, endResponse, false);
2289 public void RedirectToRoute(object routeValues) {
2290 RedirectToRoute(new RouteValueDictionary(routeValues));
2293 public void RedirectToRoute(string routeName) {
2294 RedirectToRoute(routeName, (RouteValueDictionary)null, false);
2297 public void RedirectToRoute(RouteValueDictionary routeValues) {
2298 RedirectToRoute(null /* routeName */, routeValues, false);
2301 public void RedirectToRoute(string routeName, object routeValues) {
2302 RedirectToRoute(routeName, new RouteValueDictionary(routeValues), false);
2305 public void RedirectToRoute(string routeName, RouteValueDictionary routeValues) {
2306 RedirectToRoute(routeName, routeValues, false);
2309 private void RedirectToRoute(string routeName, RouteValueDictionary routeValues, bool permanent) {
2310 string destinationUrl = null;
2311 VirtualPathData data = RouteTable.Routes.GetVirtualPath(Request.RequestContext, routeName, routeValues);
2313 destinationUrl = data.VirtualPath;
2316 if (String.IsNullOrEmpty(destinationUrl)) {
2317 throw new InvalidOperationException(SR.GetString(SR.No_Route_Found_For_Redirect));
2320 Redirect(destinationUrl, false /* endResponse */, permanent);
2323 public void RedirectToRoutePermanent(object routeValues) {
2324 RedirectToRoutePermanent(new RouteValueDictionary(routeValues));
2327 public void RedirectToRoutePermanent(string routeName) {
2328 RedirectToRoute(routeName, (RouteValueDictionary)null, true);
2331 public void RedirectToRoutePermanent(RouteValueDictionary routeValues) {
2332 RedirectToRoute(null /* routeName */, routeValues, true);
2335 public void RedirectToRoutePermanent(string routeName, object routeValues) {
2336 RedirectToRoute(routeName, new RouteValueDictionary(routeValues), true);
2339 public void RedirectToRoutePermanent(string routeName, RouteValueDictionary routeValues) {
2340 RedirectToRoute(routeName, routeValues, true);
2345 /// <para>Redirects a client to a new URL with a 301.</para>
2347 [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
2348 Justification="Warning was suppressed for consistency with existing similar Redirect API")]
2349 public void RedirectPermanent(String url) {
2350 Redirect(url, true, true);
2354 /// <para>Redirects a client to a new URL with a 301.</para>
2356 [SuppressMessage("Microsoft.Design", "CA1054:UriParametersShouldNotBeStrings",
2357 Justification = "Warning was suppressed for consistency with existing similar Redirect API")]
2358 public void RedirectPermanent(String url, bool endResponse) {
2359 Redirect(url, endResponse, true);
2362 internal void Redirect(String url, bool endResponse, bool permanent) {
2364 string originalUrl = url;
2367 throw new ArgumentNullException("url");
2369 if (url.IndexOf('\n') >= 0)
2370 throw new ArgumentException(SR.GetString(SR.Cannot_redirect_to_newline));
2372 if (_headersWritten)
2373 throw new HttpException(SR.GetString(SR.Cannot_redirect_after_headers_sent));
2375 Page page = _context.Handler as Page;
2376 if ((page != null) && page.IsCallback) {
2377 throw new ApplicationException(SR.GetString(SR.Redirect_not_allowed_in_callback));
2380 url = ApplyRedirectQueryStringIfRequired(url);
2382 url = ApplyAppPathModifier(url);
2384 url = ConvertToFullyQualifiedRedirectUrlIfRequired(url);
2386 url = UrlEncodeRedirect(url);
2390 // If it's a Page and SmartNavigation is on, return a short script
2391 // to perform the redirect instead of returning a 302 (bugs ASURT 82331/86782)
2392 #pragma warning disable 0618 // To avoid SmartNavigation deprecation warning
2393 if (page != null && page.IsPostBack && page.SmartNavigation && (Request["__smartNavPostBack"] == "true")) {
2394 #pragma warning restore 0618
2395 Write("<BODY><ASP_SMARTNAV_RDIR url=\"");
2396 Write(HttpUtility.HtmlEncode(url));
2397 Write("\"></ASP_SMARTNAV_RDIR>");
2402 this.StatusCode = permanent ? 301 : 302;
2403 RedirectLocation = url;
2404 // DevDivBugs 158137: 302 Redirect vulnerable to XSS
2405 // A ---- of protocol identifiers. We don't want to UrlEncode
2406 // URLs matching these schemes in order to not break the
2407 // physical Object Moved to link.
2408 if (UriUtil.IsSafeScheme(url)) {
2409 url = HttpUtility.HtmlAttributeEncode(url);
2412 url = HttpUtility.HtmlAttributeEncode(HttpUtility.UrlEncode(url));
2414 Write("<html><head><title>Object moved</title></head><body>\r\n");
2415 Write("<h2>Object moved to <a href=\"" + url + "\">here</a>.</h2>\r\n");
2416 Write("</body></html>\r\n");
2419 _isRequestBeingRedirected = true;
2422 Debug.Trace("ClientUrl", "*** Redirect (" + originalUrl + ") --> " + RedirectLocation + " ***");
2425 var redirectingHandler = Redirecting;
2426 if (redirectingHandler != null) {
2427 redirectingHandler(this, EventArgs.Empty);
2434 internal string ApplyRedirectQueryStringIfRequired(string url) {
2435 if (Request == null || (string)Request.Browser["requiresPostRedirectionHandling"] != "true")
2438 Page page = _context.Handler as Page;
2439 if (page != null && !page.IsPostBack)
2442 //do not add __redir=1 if it already exists
2443 int i = url.IndexOf(RedirectQueryStringAssignment, StringComparison.Ordinal);
2445 i = url.IndexOf('?');
2447 url = url.Insert(i + 1, _redirectQueryStringInline);
2450 url = String.Concat(url, _redirectQueryString);
2457 // Redirect to error page appending ?aspxerrorpath if no query string in the url.
2458 // Fails to redirect if request is already for error page.
2459 // Suppresses all errors.
2460 // See comments on RedirectToErrorPageStatus type for meaning of return values.
2462 internal RedirectToErrorPageStatus RedirectToErrorPage(String url, CustomErrorsRedirectMode redirectMode) {
2463 const String qsErrorMark = "aspxerrorpath";
2466 if (String.IsNullOrEmpty(url))
2467 return RedirectToErrorPageStatus.NotAttempted; // nowhere to redirect
2469 if (_headersWritten)
2470 return RedirectToErrorPageStatus.NotAttempted;
2472 if (Request.QueryString[qsErrorMark] != null)
2473 return RedirectToErrorPageStatus.Failed; // already in error redirect
2475 if (redirectMode == CustomErrorsRedirectMode.ResponseRewrite) {
2476 Context.Server.Execute(url);
2479 // append query string
2480 if (url.IndexOf('?') < 0)
2481 url = url + "?" + qsErrorMark + "=" + HttpEncoderUtility.UrlEncodeSpaces(Request.Path);
2483 // redirect without response.end
2484 Redirect(url, false /*endResponse*/);
2488 return RedirectToErrorPageStatus.Failed;
2491 return RedirectToErrorPageStatus.Success;
2494 // Represents the result of calling RedirectToErrorPage
2495 internal enum RedirectToErrorPageStatus {
2496 NotAttempted, // Redirect or rewrite was not attempted, possibly because no redirect URL was specified
2497 Success, // Redirect or rewrite was attempted and succeeded
2498 Failed // Redirect or rewrite was attempted and failed, possibly due to the error page throwing
2501 // Implementation of the DefaultHttpHandler for IIS6+
2502 internal bool CanExecuteUrlForEntireResponse {
2504 // if anything is sent, too late
2505 if (_headersWritten) {
2509 // must have the right kind of worker request
2510 if (_wr == null || !_wr.SupportsExecuteUrl) {
2514 // must not be capturing output to custom writer
2515 if (!UsingHttpWriter) {
2519 // there is some cached output not yet sent
2520 if (_httpWriter.GetBufferedLength() != 0) {
2524 // can't use execute url with filter installed
2525 if (_httpWriter.FilterInstalled) {
2529 if (_cachePolicy != null && _cachePolicy.IsModified()) {
2537 [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "This is a safe critical method.")]
2538 internal IAsyncResult BeginExecuteUrlForEntireResponse(
2539 String pathOverride, NameValueCollection requestHeaders,
2540 AsyncCallback cb, Object state) {
2541 Debug.Assert(CanExecuteUrlForEntireResponse);
2543 // prepare user information
2544 String userName, userAuthType;
2545 if (_context != null && _context.User != null) {
2546 userName = _context.User.Identity.Name;
2547 userAuthType = _context.User.Identity.AuthenticationType;
2550 userName = String.Empty;
2551 userAuthType = String.Empty;
2555 String path = Request.RewrittenUrl; // null is ok
2557 if (pathOverride != null) {
2558 path = pathOverride;
2562 String headers = null;
2564 if (requestHeaders != null) {
2565 int numHeaders = requestHeaders.Count;
2567 if (numHeaders > 0) {
2568 StringBuilder sb = new StringBuilder();
2570 for (int i = 0; i < numHeaders; i++) {
2571 sb.Append(requestHeaders.GetKey(i));
2573 sb.Append(requestHeaders.Get(i));
2577 headers = sb.ToString();
2581 byte[] entity = null;
2582 if (_context != null && _context.Request != null) {
2583 entity = _context.Request.EntityBody;
2586 Debug.Trace("ExecuteUrl", "HttpResponse.BeginExecuteUrlForEntireResponse:" +
2587 " path=" + path + " headers=" + headers +
2588 " userName=" + userName + " authType=" + userAuthType);
2590 // call worker request to start async execute url for this request
2591 IAsyncResult ar = _wr.BeginExecuteUrl(
2593 null, // this method
2595 true, // let execute url send headers
2596 true, // add user info
2604 // suppress further sends from ASP.NET
2605 // (only if succeeded starting async operation - not is 'finally' block)
2606 _headersWritten = true;
2612 internal void EndExecuteUrlForEntireResponse(IAsyncResult result) {
2613 Debug.Trace("ExecuteUrl", "HttpResponse.EndExecuteUrlForEntireResponse");
2614 _wr.EndExecuteUrl(result);
2617 // Methods to write from file
2619 // Writes values to an HTTP output content stream.
2620 public void Write(String s) {
2624 // Writes values to an HTTP output content stream.
2625 public void Write(Object obj) {
2631 /// <para>Writes values to an HTTP output content stream.</para>
2633 public void Write(char ch) {
2639 /// <para>Writes values to an HTTP output content stream.</para>
2641 public void Write(char[] buffer, int index, int count) {
2642 _writer.Write(buffer, index, count);
2647 /// <para>Writes a substition block to the response.</para>
2649 public void WriteSubstitution(HttpResponseSubstitutionCallback callback) {
2650 // cannot be instance method on a control
2651 if (callback.Target != null && callback.Target is Control) {
2652 throw new ArgumentException(SR.GetString(SR.Invalid_substitution_callback), "callback");
2655 if (UsingHttpWriter) {
2656 // HttpWriter can take substitution blocks
2657 _httpWriter.WriteSubstBlock(callback, _wr as IIS7WorkerRequest);
2660 // text writer -- write as string
2661 _writer.Write(callback(_context));
2664 // set the cache policy: reduce cachability from public to server
2665 if (_cachePolicy != null && _cachePolicy.GetCacheability() == HttpCacheability.Public)
2666 _cachePolicy.SetCacheability(HttpCacheability.Server);
2670 * Helper method to write from file stream
2672 * Handles only TextWriter case. For real requests
2673 * HttpWorkerRequest can take files
2675 private void WriteStreamAsText(Stream f, long offset, long size) {
2677 size = f.Length - offset;
2681 f.Seek(offset, SeekOrigin.Begin);
2683 byte[] fileBytes = new byte[(int)size];
2684 int bytesRead = f.Read(fileBytes, 0, (int)size);
2685 _writer.Write(Encoding.Default.GetChars(fileBytes, 0, bytesRead));
2689 // support for VirtualPathProvider
2690 internal void WriteVirtualFile(VirtualFile vf) {
2691 Debug.Trace("WriteVirtualFile", vf.Name);
2693 using (Stream s = vf.Open()) {
2694 if (UsingHttpWriter) {
2695 long size = s.Length;
2698 // write as memory block
2699 byte[] fileBytes = new byte[(int)size];
2700 int bytesRead = s.Read(fileBytes, 0, (int) size);
2701 _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2705 // Write file contents
2706 WriteStreamAsText(s, 0, -1);
2711 // Helper method to get absolute physical filename from the argument to WriteFile
2712 private String GetNormalizedFilename(String fn) {
2713 // If it's not a physical path, call MapPath on it
2714 if (!UrlPath.IsAbsolutePhysicalPath(fn)) {
2715 if (Request != null)
2716 fn = Request.MapPath(fn); // relative to current request
2718 fn = HostingEnvironment.MapPath(fn);
2725 /// Writes a named file directly to an HTTP content output stream.
2726 public void WriteFile(String filename) {
2727 if (filename == null) {
2728 throw new ArgumentNullException("filename");
2731 WriteFile(filename, false);
2737 * @param filename file to write
2738 * @readIntoMemory flag to read contents into memory immediately
2742 /// <para> Reads a file into a memory block.</para>
2744 public void WriteFile(String filename, bool readIntoMemory) {
2745 if (filename == null) {
2746 throw new ArgumentNullException("filename");
2749 filename = GetNormalizedFilename(filename);
2751 FileStream f = null;
2754 f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2756 if (UsingHttpWriter) {
2757 long size = f.Length;
2760 if (readIntoMemory) {
2761 // write as memory block
2762 byte[] fileBytes = new byte[(int)size];
2763 int bytesRead = f.Read(fileBytes, 0, (int) size);
2764 _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2767 // write as file block
2768 f.Close(); // close before writing
2770 _httpWriter.WriteFile(filename, 0, size);
2775 // Write file contents
2776 WriteStreamAsText(f, 0, -1);
2786 public void TransmitFile(string filename) {
2787 TransmitFile(filename, 0, -1);
2789 public void TransmitFile(string filename, long offset, long length) {
2790 if (filename == null) {
2791 throw new ArgumentNullException("filename");
2794 throw new ArgumentException(SR.GetString(SR.Invalid_range), "offset");
2796 throw new ArgumentException(SR.GetString(SR.Invalid_range), "length");
2798 filename = GetNormalizedFilename(filename);
2801 using (FileStream f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)) {
2803 // length of -1 means send rest of file
2805 length = size - offset;
2807 if (size < offset) {
2808 throw new ArgumentException(SR.GetString(SR.Invalid_range), "offset");
2810 else if ((size - offset) < length) {
2811 throw new ArgumentException(SR.GetString(SR.Invalid_range), "length");
2813 if (!UsingHttpWriter) {
2814 WriteStreamAsText(f, offset, length);
2820 bool supportsLongTransmitFile = (_wr != null && _wr.SupportsLongTransmitFile);
2822 _httpWriter.TransmitFile(filename, offset, length,
2823 _context.IsClientImpersonationConfigured || HttpRuntime.IsOnUNCShareInternal, supportsLongTransmitFile);
2828 private void ValidateFileRange(String filename, long offset, long length) {
2829 FileStream f = null;
2832 f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2834 long fileSize = f.Length;
2837 length = fileSize - offset;
2839 if (offset < 0 || length > fileSize - offset)
2840 throw new HttpException(SR.GetString(SR.Invalid_range));
2851 * @param filename file to write
2852 * @param offset file offset to start writing
2853 * @param size number of bytes to write
2857 /// <para>Writes a file directly to an HTTP content output stream.</para>
2859 public void WriteFile(String filename, long offset, long size) {
2860 if (filename == null) {
2861 throw new ArgumentNullException("filename");
2867 filename = GetNormalizedFilename(filename);
2869 ValidateFileRange(filename, offset, size);
2871 if (UsingHttpWriter) {
2872 // HttpWriter can take files -- don't open here (but Demand permission)
2873 InternalSecurityPermissions.FileReadAccess(filename).Demand();
2874 _httpWriter.WriteFile(filename, offset, size);
2877 FileStream f = null;
2880 f = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
2881 WriteStreamAsText(f, offset, size);
2893 * @param handle file to write
2894 * @param offset file offset to start writing
2895 * @param size number of bytes to write
2899 /// <para>Writes a file directly to an HTTP content output stream.</para>
2901 [SecurityPermission(SecurityAction.Demand, UnmanagedCode=true)]
2902 public void WriteFile(IntPtr fileHandle, long offset, long size) {
2906 FileStream f = null;
2909 f = new FileStream(new Microsoft.Win32.SafeHandles.SafeFileHandle(fileHandle,false), FileAccess.Read);
2911 if (UsingHttpWriter) {
2912 long fileSize = f.Length;
2915 size = fileSize - offset;
2917 if (offset < 0 || size > fileSize - offset)
2918 throw new HttpException(SR.GetString(SR.Invalid_range));
2921 f.Seek(offset, SeekOrigin.Begin);
2923 // write as memory block
2924 byte[] fileBytes = new byte[(int)size];
2925 int bytesRead = f.Read(fileBytes, 0, (int)size);
2926 _httpWriter.WriteBytes(fileBytes, 0, bytesRead);
2929 WriteStreamAsText(f, offset, size);
2939 /// <para>Allows HTTP/2 Server Push</para>
2941 public void PushPromise(string path) {
2945 PushPromise(path, method: "GET", headers: null);
2949 /// <para>Allows HTTP/2 Server Push</para>
2951 public void PushPromise(string path, string method, NameValueCollection headers) {
2952 // PushPromise is non-deterministic and application shouldn't have logic that depends on it.
2953 // It's only purpose is performance advantage in some cases.
2954 // There are many conditions (protocol and implementation) that may cause to
2955 // ignore the push requests completely.
2956 // The expectation is based on fire-and-forget
2959 throw new ArgumentNullException("path");
2962 if (method == null) {
2963 throw new ArgumentNullException("method");
2966 // Extract an optional query string
2967 string queryString = string.Empty;
2968 int i = path.IndexOf('?');
2971 if (i < path.Length - 1) {
2972 queryString = path.Substring(i + 1);
2975 // Remove the query string portion from the path
2976 path = path.Substring(0, i);
2980 // Only virtual path is allowed:
2981 // "/path" - origin relative
2982 // "~/path" - app relative
2983 // "path" - request relative
2984 // "../path" - reduced
2985 if (string.IsNullOrEmpty(path) || !UrlPath.IsValidVirtualPathWithoutProtocol(path)) {
2986 throw new ArgumentException(SR.GetString(SR.Invalid_path_for_push_promise, path));
2989 VirtualPath virtualPath = Request.FilePathObject.Combine(VirtualPath.Create(path));
2992 if (!HttpRuntime.UseIntegratedPipeline) {
2993 throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode));
2997 IIS7WorkerRequest wr = (IIS7WorkerRequest) _wr;
2998 wr.PushPromise(virtualPath.VirtualPathString, queryString, method, headers);
3000 catch (PlatformNotSupportedException e) {
3001 // Ignore errors if push promise is not supported
3002 if (Context.TraceIsEnabled) {
3003 Context.Trace.Write("aspx", "Push promise is not supported", e);
3009 // Deprecated ASP compatibility methods and properties
3015 /// Same as StatusDescription. Provided only for ASP compatibility.
3018 public string Status {
3020 return this.StatusCode.ToString(NumberFormatInfo.InvariantInfo) + " " + this.StatusDescription;
3025 String descr = "OK";
3028 int i = value.IndexOf(' ');
3029 code = Int32.Parse(value.Substring(0, i), CultureInfo.InvariantCulture);
3030 descr = value.Substring(i+1);
3033 throw new HttpException(SR.GetString(SR.Invalid_status_string));
3036 this.StatusCode = code;
3037 this.StatusDescription = descr;
3044 /// Same as BufferOutput. Provided only for ASP compatibility.
3047 public bool Buffer {
3048 get { return this.BufferOutput;}
3049 set { this.BufferOutput = value;}
3054 /// <para>Same as Appendheader. Provided only for ASP compatibility.</para>
3056 public void AddHeader(String name, String value) {
3057 AppendHeader(name, value);
3061 * Cancelles handler processing of the current request
3062 * throws special [non-]exception uncatchable by the user code
3063 * to tell application to stop module execution.
3067 /// <para>Sends all currently buffered output to the client then closes the
3068 /// socket connection.</para>
3071 if (_context.IsInCancellablePeriod) {
3072 AbortCurrentThread();
3075 // when cannot abort execution, flush and supress further output
3076 _endRequiresObservation = true;
3078 if (!_flushing) { // ignore Reponse.End while flushing (in OnPreSendHeaders)
3082 if (_context.ApplicationInstance != null) {
3083 _context.ApplicationInstance.CompleteRequest();
3089 // Aborts the current thread if Response.End was called and not yet observed.
3090 internal void ObserveResponseEndCalled() {
3091 if (_endRequiresObservation) {
3092 _endRequiresObservation = false;
3093 AbortCurrentThread();
3097 [SuppressMessage("Microsoft.Security", "CA2106:SecureAsserts", Justification = "Known issue, but required for proper operation of ASP.NET.")]
3098 [SecurityPermission(SecurityAction.Assert, ControlThread = true)]
3099 private static void AbortCurrentThread() {
3100 Thread.CurrentThread.Abort(new HttpApplication.CancelModuleException(false));
3104 * ASP compatible caching properties
3110 /// Gets or sets the time, in minutes, until cached
3111 /// information will be removed from the cache. Provided for ASP compatiblility. Use
3112 /// the <see cref='System.Web.HttpResponse.Cache'/>
3113 /// Property instead.
3116 public int Expires {
3118 return _expiresInMinutes;
3121 if (!_expiresInMinutesSet || value < _expiresInMinutes) {
3122 _expiresInMinutes = value;
3123 Cache.SetExpires(_context.Timestamp + new TimeSpan(0, _expiresInMinutes, 0));
3131 /// Gets or sets the absolute time that cached information
3132 /// will be removed from the cache. Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
3133 /// property instead.
3136 public DateTime ExpiresAbsolute {
3138 return _expiresAbsolute;
3141 if (!_expiresAbsoluteSet || value < _expiresAbsolute) {
3142 _expiresAbsolute = value;
3143 Cache.SetExpires(_expiresAbsolute);
3151 /// Provided for ASP compatiblility. Use the <see cref='System.Web.HttpResponse.Cache'/>
3152 /// property instead.
3155 public string CacheControl {
3157 if (_cacheControl == null) {
3162 return _cacheControl;
3165 if (String.IsNullOrEmpty(value)) {
3166 _cacheControl = null;
3167 Cache.SetCacheability(HttpCacheability.NoCache);
3169 else if (StringUtil.EqualsIgnoreCase(value, "private")) {
3170 _cacheControl = value;
3171 Cache.SetCacheability(HttpCacheability.Private);
3173 else if (StringUtil.EqualsIgnoreCase(value, "public")) {
3174 _cacheControl = value;
3175 Cache.SetCacheability(HttpCacheability.Public);
3177 else if (StringUtil.EqualsIgnoreCase(value, "no-cache")) {
3178 _cacheControl = value;
3179 Cache.SetCacheability(HttpCacheability.NoCache);
3182 throw new ArgumentException(SR.GetString(SR.Invalid_value_for_CacheControl, value));
3187 internal void SetAppPathModifier(string appPathModifier) {
3188 if (appPathModifier != null && (
3189 appPathModifier.Length == 0 ||
3190 appPathModifier[0] == '/' ||
3191 appPathModifier[appPathModifier.Length - 1] == '/')) {
3193 throw new ArgumentException(SR.GetString(SR.InvalidArgumentValue, "appPathModifier"));
3196 _appPathModifier = appPathModifier;
3198 Debug.Trace("ClientUrl", "*** SetAppPathModifier (" + appPathModifier + ") ***");
3202 public string ApplyAppPathModifier(string virtualPath) {
3204 string originalUrl = virtualPath;
3206 object ch = _context.CookielessHelper; // This ensures that the cookieless-helper is initialized and applies the AppPathModifier
3207 if (virtualPath == null)
3210 if (UrlPath.IsRelativeUrl(virtualPath)) {
3211 // DevDiv 173208: RewritePath returns an HTTP 500 error code when requested with certain user agents
3212 // We should use ClientBaseDir instead of FilePathObject.
3213 virtualPath = UrlPath.Combine(Request.ClientBaseDir.VirtualPathString, virtualPath);
3216 // ignore paths with http://server/... or //
3217 if (!UrlPath.IsRooted(virtualPath) || virtualPath.StartsWith("//", StringComparison.Ordinal)) {
3221 virtualPath = UrlPath.Reduce(virtualPath);
3224 if (_appPathModifier == null || virtualPath.IndexOf(_appPathModifier, StringComparison.Ordinal) >= 0) {
3226 Debug.Trace("ClientUrl", "*** ApplyAppPathModifier (" + originalUrl + ") --> " + virtualPath + " ***");
3231 string appPath = HttpRuntime.AppDomainAppVirtualPathString;
3233 int compareLength = appPath.Length;
3234 bool isVirtualPathShort = (virtualPath.Length == appPath.Length - 1);
3235 if (isVirtualPathShort) {
3239 // String.Compare will throw exception if there aren't compareLength characters
3240 if (virtualPath.Length < compareLength) {
3244 if (!StringUtil.EqualsIgnoreCase(virtualPath, 0, appPath, 0, compareLength)) {
3248 if (isVirtualPathShort) {
3252 Debug.Assert(virtualPath.Length >= appPath.Length);
3253 if (virtualPath.Length == appPath.Length) {
3254 virtualPath = virtualPath.Substring(0, appPath.Length) + _appPathModifier + "/";
3258 virtualPath.Substring(0, appPath.Length) +
3261 virtualPath.Substring(appPath.Length);
3264 Debug.Trace("ClientUrl", "*** ApplyAppPathModifier (" + originalUrl + ") --> " + virtualPath + " ***");
3270 internal String RemoveAppPathModifier(string virtualPath) {
3271 if (String.IsNullOrEmpty(_appPathModifier))
3274 int pos = virtualPath.IndexOf(_appPathModifier, StringComparison.Ordinal);
3276 if (pos <= 0 || virtualPath[pos-1] != '/')
3279 return virtualPath.Substring(0, pos-1) + virtualPath.Substring(pos + _appPathModifier.Length);
3282 internal bool UsePathModifier {
3284 return !String.IsNullOrEmpty(_appPathModifier);
3288 private String ConvertToFullyQualifiedRedirectUrlIfRequired(String url) {
3289 HttpRuntimeSection runtimeConfig = RuntimeConfig.GetConfig(_context).HttpRuntime;
3290 if ( runtimeConfig.UseFullyQualifiedRedirectUrl ||
3291 (Request != null && (string)Request.Browser["requiresFullyQualifiedRedirectUrl"] == "true")) {
3292 return (new Uri(Request.Url, url)).AbsoluteUri ;
3299 private String UrlEncodeIDNSafe(String url) {
3300 // Bug 86594: Should not encode the domain part of the url. For example,
3301 // http://Übersite/Überpage.aspx should only encode the 2nd Ü.
3302 // To accomplish this we must separate the scheme+host+port portion of the url from the path portion,
3303 // encode the path portion, then reconstruct the url.
3304 Debug.Assert(!url.Contains("?"), "Querystring should have been stripped off.");
3306 string schemeAndAuthority;
3308 string queryAndFragment;
3309 bool isValidUrl = UriUtil.TrySplitUriForPathEncode(url, out schemeAndAuthority, out path, out queryAndFragment, checkScheme: true);
3312 // only encode the path portion
3313 return schemeAndAuthority + HttpEncoderUtility.UrlEncodeSpaces(HttpUtility.UrlEncodeNonAscii(path, Encoding.UTF8)) + queryAndFragment;
3316 // encode the entire URL
3317 return HttpEncoderUtility.UrlEncodeSpaces(HttpUtility.UrlEncodeNonAscii(url, Encoding.UTF8));
3321 private String UrlEncodeRedirect(String url) {
3322 // convert all non-ASCII chars before ? to %XX using UTF-8 and
3323 // after ? using Response.ContentEncoding
3325 int iqs = url.IndexOf('?');
3328 Encoding qsEncoding = (Request != null) ? Request.ContentEncoding : ContentEncoding;
3329 url = UrlEncodeIDNSafe(url.Substring(0, iqs)) + HttpUtility.UrlEncodeNonAscii(url.Substring(iqs), qsEncoding);
3332 url = UrlEncodeIDNSafe(url);
3338 internal void UpdateNativeResponse(bool sendHeaders)
3340 IIS7WorkerRequest iis7WorkerRequest = _wr as IIS7WorkerRequest;
3342 if (null == iis7WorkerRequest) {
3346 // WOS 1841024 - Don't set _suppressContent to true for HEAD requests. IIS needs the content
3347 // in order to correctly set the Content-Length header.
3348 // WOS 1634512 - need to clear buffers if _ended == true
3349 // WOS 1850019 - Breaking Change: ASP.NET v2.0: Content-Length is not correct for pages that call HttpResponse.SuppressContent
3350 if ((_suppressContent && Request != null && Request.HttpVerb != HttpVerb.HEAD) || _ended)
3353 bool needPush = false;
3354 // NOTE: This also sets the response encoding on the HttpWriter
3355 long bufferedLength = _httpWriter.GetBufferedLength();
3358 // Set headers and status
3360 if (!_headersWritten)
3365 // VSWhidbey 270635: We need to reset the status code for mobile devices.
3366 if (UseAdaptiveError) {
3368 // VSWhidbey 288054: We should change the status code for cases
3369 // that cannot be handled by mobile devices
3370 // 4xx for Client Error and 5xx for Server Error in HTTP spec
3371 int statusCode = StatusCode;
3372 if (statusCode >= 400 && statusCode < 600) {
3373 this.StatusCode = 200;
3377 // DevDiv #782830: Provide a hook where the application can change the response status code
3378 // or response headers.
3379 if (sendHeaders && !_onSendingHeadersSubscriptionQueue.IsEmpty) {
3380 _onSendingHeadersSubscriptionQueue.FireAndComplete(cb => cb(Context));
3384 _wr.SendStatus(this.StatusCode, this.SubStatusCode, this.StatusDescription);
3391 if (!_suppressHeaders && !_clientDisconnected)
3394 EnsureSessionStateIfNecessary();
3397 // If redirect location set, write it through to IIS as a header
3398 if (_redirectLocation != null && _redirectLocationSet) {
3399 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3400 headers.Set("Location", _redirectLocation);
3401 _redirectLocationSet = false;
3404 // Check if there is buffered response
3405 bool responseBuffered = bufferedLength > 0 || iis7WorkerRequest.IsResponseBuffered();
3408 // Generate Content-Type
3410 if (_contentType != null // Valid Content-Type
3411 && (_contentTypeSetByManagedCaller // Explicitly set by managed caller
3412 || (_contentTypeSetByManagedHandler && responseBuffered))) { // Implicitly set by managed handler and response is non-empty
3413 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3414 String contentType = AppendCharSetToContentType(_contentType);
3415 headers.Set("Content-Type", contentType);
3419 // If cookies have been added/changed, set the corresponding headers
3421 GenerateResponseHeadersForCookies();
3423 // Not calling WriteHeaders headers in Integrated mode.
3424 // Instead, most headers are generated when the handler runs,
3425 // or on demand as necessary.
3426 // The only exception are the cache policy headers.
3429 SuppressCachingCookiesIfNecessary();
3431 if (_cachePolicy != null) {
3432 if (_cachePolicy.IsModified()) {
3433 ArrayList cacheHeaders = new ArrayList();
3434 _cachePolicy.GetHeaders(cacheHeaders, this);
3435 HttpHeaderCollection headers = Headers as HttpHeaderCollection;
3436 foreach (HttpResponseHeader header in cacheHeaders) {
3437 // set and override the header
3438 headers.Set(header.Name, header.Value);
3448 if (_flushing && !_filteringCompleted) {
3449 _httpWriter.FilterIntegrated(false, iis7WorkerRequest);
3450 bufferedLength = _httpWriter.GetBufferedLength();
3453 if (!_clientDisconnected && (bufferedLength > 0 || needPush)) {
3455 if (bufferedLength == 0 ) {
3456 if (_httpWriter.IgnoringFurtherWrites) {
3461 // push HttpWriter buffers to worker request
3462 _httpWriter.Send(_wr);
3463 // push buffers through into native
3464 iis7WorkerRequest.PushResponseToNative();
3465 // dispose them (since they're copied or
3466 // owned by native request)
3467 _httpWriter.DisposeIntegratedBuffers();
3471 private void ClearNativeResponse(bool clearEntity, bool clearHeaders, IIS7WorkerRequest wr) {
3472 wr.ClearResponse(clearEntity, clearHeaders);
3474 _httpWriter.ClearSubstitutionBlocks();
3478 private void SuppressCachingCookiesIfNecessary() {
3479 // MSRC 11855 (DevDiv 297240 / 362405)
3480 // We should suppress caching cookies if non-shareable cookies are
3481 // present in the response. Since these cookies can cary sensitive information,
3482 // we should set Cache-Control: no-cache=set-cookie if there is such cookie
3483 // This prevents all well-behaved caches (both intermediary proxies and any local caches
3484 // on the client) from storing this sensitive information.
3486 // Additionally, we should not set this header during an SSL request, as certain versions
3487 // of IE don't handle it properly and simply refuse to render the page. More info:
3488 // http://blogs.msdn.com/b/ieinternals/archive/2009/10/02/internet-explorer-cannot-download-over-https-when-no-cache.aspx
3490 // Finally, we don't need to set 'no-cache' if the response is not publicly cacheable,
3491 // as ASP.NET won't cache the response (due to the cookies) and proxies won't cache
3492 // the response (due to Cache-Control: private).
3493 // If _cachePolicy isn't set, then Cache.GetCacheability() will contruct a default one (which causes Cache-Control: private)
3494 if (!Request.IsSecureConnection && ContainsNonShareableCookies() && Cache.GetCacheability() == HttpCacheability.Public) {
3495 Cache.SetCacheability(HttpCacheability.NoCache, "Set-Cookie");
3498 // if there are any cookies, do not kernel cache the response
3499 if (_cachePolicy != null && _cookies != null && _cookies.Count != 0) {
3500 _cachePolicy.SetHasSetCookieHeader();
3501 // In integrated mode, the cookies will eventually be sent to IIS via IIS7WorkerRequest.SetUnknownResponseHeader,
3502 // where we will disable both HTTP.SYS kernel cache and IIS user mode cache (DevDiv 113142 & 255268). In classic
3503 // mode, the cookies will be sent to IIS via ISAPIWorkerRequest.SendUnknownResponseHeader and
3504 // ISAPIWorkerRequest.SendKnownResponseHeader (DevDiv 113142), where we also disables the kernel cache. So the
3505 // call of DisableKernelCache below is not really needed.
3506 DisableKernelCache();
3510 private void EnsureSessionStateIfNecessary() {
3511 // Ensure the session state is in complete state before sending the response headers
3512 // Due to optimization and delay initialization sometimes we create and store the session state id in ReleaseSessionState.
3513 // But it's too late in case of Flush. Session state id must be written (if used) before sending the headers.
3514 if (AppSettings.EnsureSessionStateLockedOnFlush) {
3515 _context.EnsureSessionStateIfNecessary();
3520 internal enum CacheDependencyType {
3526 struct ResponseDependencyList {
3527 private ArrayList _dependencies;
3528 private string[] _dependencyArray;
3529 private DateTime _oldestDependency;
3530 private string _requestVirtualPath;
3532 internal void AddDependency(string item, string argname) {
3534 throw new ArgumentNullException(argname);
3537 _dependencyArray = null;
3539 if (_dependencies == null) {
3540 _dependencies = new ArrayList(1);
3543 DateTime utcNow = DateTime.UtcNow;
3545 _dependencies.Add(new ResponseDependencyInfo(
3546 new string[] {item}, utcNow));
3548 // _oldestDependency is initialized to MinValue and indicates that it must always be set
3549 if (_oldestDependency == DateTime.MinValue || utcNow < _oldestDependency)
3550 _oldestDependency = utcNow;
3553 internal void AddDependencies(ArrayList items, string argname) {
3554 if (items == null) {
3555 throw new ArgumentNullException(argname);
3558 string[] a = (string[]) items.ToArray(typeof(string));
3559 AddDependencies(a, argname, false);
3562 internal void AddDependencies(string[] items, string argname) {
3563 AddDependencies(items, argname, true);
3566 internal void AddDependencies(string[] items, string argname, bool cloneArray) {
3567 AddDependencies(items, argname, cloneArray, DateTime.UtcNow);
3570 internal void AddDependencies(string[] items, string argname, bool cloneArray, string requestVirtualPath) {
3571 if (requestVirtualPath == null)
3572 throw new ArgumentNullException("requestVirtualPath");
3574 _requestVirtualPath = requestVirtualPath;
3575 AddDependencies(items, argname, cloneArray, DateTime.UtcNow);
3578 internal void AddDependencies(string[] items, string argname, bool cloneArray, DateTime utcDepTime) {
3579 if (items == null) {
3580 throw new ArgumentNullException(argname);
3583 string [] itemsLocal;
3586 itemsLocal = (string[]) items.Clone();
3592 foreach (string item in itemsLocal) {
3593 if (String.IsNullOrEmpty(item)) {
3594 throw new ArgumentNullException(argname);
3598 _dependencyArray = null;
3600 if (_dependencies == null) {
3601 _dependencies = new ArrayList(1);
3604 _dependencies.Add(new ResponseDependencyInfo(itemsLocal, utcDepTime));
3606 // _oldestDependency is initialized to MinValue and indicates that it must always be set
3607 if (_oldestDependency == DateTime.MinValue || utcDepTime < _oldestDependency)
3608 _oldestDependency = utcDepTime;
3611 internal bool HasDependencies() {
3612 if (_dependencyArray == null && _dependencies == null)
3618 internal string[] GetDependencies() {
3619 if (_dependencyArray == null && _dependencies != null) {
3621 foreach (ResponseDependencyInfo info in _dependencies) {
3622 size += info.items.Length;
3625 _dependencyArray = new string[size];
3628 foreach (ResponseDependencyInfo info in _dependencies) {
3629 int length = info.items.Length;
3630 Array.Copy(info.items, 0, _dependencyArray, index, length);
3635 return _dependencyArray;
3638 // The caller of this method must dispose the cache dependencies
3639 internal CacheDependency CreateCacheDependency(CacheDependencyType dependencyType, CacheDependency dependency) {
3640 if (_dependencies != null) {
3641 if (dependencyType == CacheDependencyType.Files
3642 || dependencyType == CacheDependencyType.CacheItems) {
3643 foreach (ResponseDependencyInfo info in _dependencies) {
3644 CacheDependency dependencyOld = dependency;
3646 if (dependencyType == CacheDependencyType.Files) {
3647 dependency = new CacheDependency(0, info.items, null, dependencyOld, info.utcDate);
3650 // We create a "public" CacheDepdency here, since the keys are for public items.
3651 dependency = new CacheDependency(null, info.items, dependencyOld,
3652 DateTimeUtil.ConvertToLocalTime(info.utcDate));
3656 if (dependencyOld != null) {
3657 dependencyOld.Dispose();
3663 CacheDependency virtualDependency = null;
3664 VirtualPathProvider vpp = HostingEnvironment.VirtualPathProvider;
3665 if (vpp != null && _requestVirtualPath != null) {
3666 virtualDependency = vpp.GetCacheDependency(_requestVirtualPath, GetDependencies(), _oldestDependency);
3668 if (virtualDependency != null) {
3669 AggregateCacheDependency tempDep = new AggregateCacheDependency();
3670 tempDep.Add(virtualDependency);
3671 if (dependency != null) {
3672 tempDep.Add(dependency);
3674 dependency = tempDep;
3683 internal class ResponseDependencyInfo {
3684 internal readonly string[] items;
3685 internal readonly DateTime utcDate;
3687 internal ResponseDependencyInfo(string[] items, DateTime utcDate) {
3689 this.utcDate = utcDate;