// Author:
// Miguel de Icaza (miguel@novell.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Marek Habersack <mhabersack@novell.com>
//
-// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
using System.Web.Hosting;
using System.Web.SessionState;
-namespace System.Web {
-
+#if NET_4_0
+using System.Web.Routing;
+#endif
+
+namespace System.Web
+{
// CAS - no InheritanceDemand here as the class is sealed
[AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
- public sealed partial class HttpResponse {
+ public sealed partial class HttpResponse
+ {
internal HttpWorkerRequest WorkerRequest;
internal HttpResponseStream output_stream;
internal bool buffer = true;
CachedRawResponse cached_response;
string user_cache_control = "private";
string redirect_location;
-
- static UnknownResponseHeader version_header;
+ string version_header;
+ bool version_header_checked;
//
// Negative Content-Length means we auto-compute the size of content-length
// The list of the headers that we will send back to the client, except
// the headers that we compute here.
//
- ArrayList headers = new ArrayList ();
+
+ HttpHeaderCollection headers;
bool headers_sent;
- ArrayList cached_headers;
+ NameValueCollection cached_headers;
//
// Transfer encoding state
internal bool use_chunked;
bool closed;
+ bool completed;
internal bool suppress_content;
//
// Session State
//
string app_path_mod;
-
-#if NET_2_0
bool is_request_being_redirected;
Encoding headerEncoding;
-#endif
- static HttpResponse ()
- {
-#if NET_2_0
- HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
-#else
- HttpRuntimeConfig config = HttpContext.GetAppConfig ("system.web/httpRuntime") as HttpRuntimeConfig;
-#endif
- if (config != null && config.EnableVersionHeader) {
- string version = Environment.Version.ToString (3);
- version_header = new UnknownResponseHeader ("X-AspNet-Version", version);
- }
- }
-
internal HttpResponse ()
{
output_stream = new HttpResponseStream (this);
+ writer = new HttpWriter (this);
}
public HttpResponse (TextWriter writer) : this ()
{
+
this.writer = writer;
}
this.context = context;
#if !TARGET_J2EE
- if (worker_request != null)
- use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
+ if (worker_request != null && worker_request.GetHttpVersion () == "HTTP/1.1") {
+ string gi = worker_request.GetServerVariable ("GATEWAY_INTERFACE");
+ use_chunked = (String.IsNullOrEmpty (gi) ||
+ !gi.StartsWith ("cgi", StringComparison.OrdinalIgnoreCase));
+ } else {
+ use_chunked = false;
+ }
#endif
+ writer = new HttpWriter (this);
}
-
+
internal TextWriter SetTextWriter (TextWriter writer)
{
TextWriter prev = this.writer;
return prev;
}
+ internal string VersionHeader {
+ get {
+ if (!version_header_checked && version_header == null) {
+ version_header_checked = true;
+ HttpRuntimeSection config = HttpRuntime.Section;
+ if (config != null && config.EnableVersionHeader)
+ version_header = Environment.Version.ToString (3);
+ }
+
+ return version_header;
+ }
+ }
+
+ internal HttpContext Context {
+ get { return context; }
+ set { context = value; }
+ }
+
internal string[] FileDependencies {
get {
if (fileDependencies == null || fileDependencies.Count == 0)
output_stream.Filter = value;
}
}
-#if NET_2_0
+
public Encoding HeaderEncoding {
get {
if (headerEncoding == null) {
}
}
- [MonoTODO ("Not implemented")]
public NameValueCollection Headers {
get {
- // TODO: currently only return empty NameValueColletion
- return new NameValueCollection ();
+ if (headers == null)
+ headers = new HttpHeaderCollection ();
+
+ return headers;
}
}
-#endif
+
+
public bool IsClientConnected {
get {
if (WorkerRequest == null)
return WorkerRequest.IsClientConnected ();
}
}
-#if NET_2_0
+
public bool IsRequestBeingRedirected {
get { return is_request_being_redirected; }
}
-#endif
+
public TextWriter Output {
get {
- if (writer == null)
- writer = new HttpWriter (this);
-
return writer;
}
+#if NET_4_0
+ set { writer = value; }
+#endif
}
public Stream OutputStream {
string s = value.Substring (0, p);
-#if NET_2_0
if (!Int32.TryParse (s, out status_code))
throw new HttpException ("Invalid format for the Status property");
-#else
-
- try {
- status_code = Int32.Parse (s);
- } catch {
- throw new HttpException ("Invalid format for the Status property");
- }
-#endif
status_description = value.Substring (p+1);
}
}
+ // We ignore the two properties on Mono as they are for use with IIS7, but there is
+ // no point in throwing PlatformNotSupportedException. We might find a use for them
+ // some day.
+ public int SubStatusCode {
+ get;
+ set;
+ }
+
+ public bool TrySkipIisCustomErrors {
+ get;
+ set;
+ }
+
public int StatusCode {
get {
return status_code;
}
}
-#if NET_2_0
[MonoTODO ("Not implemented")]
public void AddCacheDependency (CacheDependency[] dependencies)
{
{
throw new NotImplementedException ();
}
-#endif
+
[MonoTODO("Currently does nothing")]
public void AddCacheItemDependencies (ArrayList cacheKeys)
{
return;
FileDependenciesArray.AddRange (filenames);
}
-#if NET_2_0
+
public void AddFileDependencies (string[] filenames)
{
if (filenames == null || filenames.Length == 0)
return;
FileDependenciesArray.AddRange (filenames);
}
-#endif
public void AddFileDependency (string filename)
{
public void AppendHeader (string name, string value)
{
if (headers_sent)
- throw new HttpException ("headers have been already sent");
-
+ throw new HttpException ("Headers have been already sent");
#if !TARGET_J2EE
- if (String.Compare (name, "content-length", true, CultureInfo.InvariantCulture) == 0){
+ if (String.Compare (name, "content-length", StringComparison.OrdinalIgnoreCase) == 0){
content_length = (long) UInt64.Parse (value);
use_chunked = false;
return;
}
#endif
- if (String.Compare (name, "content-type", true, CultureInfo.InvariantCulture) == 0){
+ if (String.Compare (name, "content-type", StringComparison.OrdinalIgnoreCase) == 0){
ContentType = value;
return;
}
#if !TARGET_J2EE
- if (String.Compare (name, "transfer-encoding", true, CultureInfo.InvariantCulture) == 0){
+ if (String.Compare (name, "transfer-encoding", StringComparison.OrdinalIgnoreCase) == 0){
transfer_encoding = value;
use_chunked = false;
return;
}
#endif
- if (String.Compare (name, "cache-control", true, CultureInfo.InvariantCulture) == 0){
+ if (String.Compare (name, "cache-control", StringComparison.OrdinalIgnoreCase) == 0){
user_cache_control = value;
return;
}
- headers.Add (new UnknownResponseHeader (name, value));
+ Headers.Add (name, value);
}
[AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
public string ApplyAppPathModifier (string virtualPath)
{
- if (virtualPath == null)
+ if (virtualPath == null || context == null)
return null;
- if (virtualPath == "")
+ if (virtualPath.Length == 0)
return context.Request.RootVirtualDir;
if (UrlUtils.IsRelativeUrl (virtualPath)) {
}
bool cookieless = false;
-#if NET_2_0
SessionStateSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/sessionState") as SessionStateSection;
cookieless = SessionStateModule.IsCookieLess (context, config);
-#else
- SessionConfig config = HttpContext.GetAppConfig ("system.web/sessionState") as SessionConfig;
- cookieless = config.CookieLess;
-#endif
+
if (!cookieless)
return virtualPath;
content_length = -1;
content_type = "text/html";
transfer_encoding = null;
- user_cache_control = null;
- headers.Clear ();
+ user_cache_control = "private";
+ if (cache_policy != null)
+ cache_policy.Cacheability = HttpCacheability.Private;
+
+ if (headers != null)
+ headers.Clear ();
}
internal bool HeadersSent {
closed = true;
}
-#if NET_2_0
public void DisableKernelCache ()
{
// does nothing in Mono
}
-#endif
public void End ()
{
// Transfer-Encoding (chunked)
// Cache-Control
// X-AspNet-Version
- void AddHeadersNoCache (ArrayList write_headers, bool final_flush)
+ void AddHeadersNoCache (NameValueCollection write_headers, bool final_flush)
{
#if !TARGET_J2EE
//
// Transfer-Encoding
//
if (use_chunked)
- write_headers.Add (new UnknownResponseHeader ("Transfer-Encoding", "chunked"));
+ write_headers.Add ("Transfer-Encoding", "chunked");
else if (transfer_encoding != null)
- write_headers.Add (new UnknownResponseHeader ("Transfer-Encoding", transfer_encoding));
+ write_headers.Add ("Transfer-Encoding", transfer_encoding);
#endif
if (redirect_location != null)
- write_headers.Add (new UnknownResponseHeader ("Location", redirect_location));
+ write_headers.Add ("Location", redirect_location);
#if !TARGET_J2EE
- if (version_header != null)
- write_headers.Add (version_header);
+ string vh = VersionHeader;
+ if (vh != null)
+ write_headers.Add ("X-AspNet-Version", vh);
//
// If Content-Length is set.
//
if (content_length >= 0) {
- write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderContentLength,
- content_length.ToString (CultureInfo.InvariantCulture)));
+ write_headers.Add (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderContentLength),
+ content_length.ToString (Helpers.InvariantCulture));
} else if (BufferOutput) {
if (final_flush) {
//
// we know the content-length.
//
content_length = output_stream.total;
- write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderContentLength,
- content_length.ToString (CultureInfo.InvariantCulture)));
+ write_headers.Add (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderContentLength),
+ content_length.ToString (Helpers.InvariantCulture));
} else {
//
// We are buffering, and this is a flush in the middle.
// If we are not chunked, we need to set "Connection: close".
//
if (use_chunked){
- write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderConnection, "close"));
+ write_headers.Add (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderConnection), "close");
}
}
} else {
// close at the end.
//
if (use_chunked){
- write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderConnection, "close"));
+ write_headers.Add (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderConnection), "close");
}
}
#endif
if (cache_policy != null)
cache_policy.SetHeaders (this, headers);
else
- write_headers.Add (new UnknownResponseHeader ("Cache-Control", CacheControl));
+ write_headers.Add ("Cache-Control", CacheControl);
//
// Content-Type
}
}
- write_headers.Add (new UnknownResponseHeader ("Content-Type", header));
+ write_headers.Add ("Content-Type", header);
}
if (cookies != null && cookies.Count != 0){
int n = cookies.Count;
for (int i = 0; i < n; i++)
- write_headers.Add (cookies.Get (i).GetCookieHeader ());
+ write_headers.Add ("Set-Cookie", cookies.Get (i).GetCookieHeaderValue ());
#if TARGET_J2EE
// For J2EE Portal support emulate cookies by storing them in the session.
context.Request.SetSessionCookiesForPortal (cookies);
// If this page is cached use the cached headers
// instead of the standard headers
- ArrayList write_headers = headers;
+ NameValueCollection write_headers;
if (cached_headers != null)
write_headers = cached_headers;
- else
+ else {
+ write_headers = Headers;
AddHeadersNoCache (write_headers, final_flush);
-
+ }
+
if (WorkerRequest != null)
WorkerRequest.SendStatus (status_code, StatusDescription);
if (WorkerRequest != null) {
- foreach (BaseResponseHeader header in write_headers){
- header.SendContent (WorkerRequest);
+ string header_name;
+ string[] values;
+ int header_index;
+
+ for (int i = 0; i < write_headers.Count; i++) {
+ header_name = write_headers.GetKey (i);
+ header_index = HttpWorkerRequest.GetKnownResponseHeaderIndex (header_name);
+ values = write_headers.GetValues (i);
+ if (values == null)
+ continue;
+
+ foreach (string val in values) {
+ if (header_index > -1)
+ WorkerRequest.SendKnownResponseHeader (header_index, val);
+ else
+ WorkerRequest.SendUnknownResponseHeader (header_name, val);
+ }
}
}
}
internal void Flush (bool final_flush)
{
+ if (completed)
+ throw new HttpException ("Server cannot flush a completed response");
+
DoFilter (final_flush);
if (!headers_sent){
if (final_flush || status_code != 200)
output_stream.Clear ();
if (WorkerRequest != null)
output_stream.Flush (WorkerRequest, true); // ignore final_flush here.
+ completed = true;
return;
}
-
+ completed = final_flush;
+
if (!headers_sent)
WriteHeaders (final_flush);
app_instance.TriggerPreSendRequestContent ();
}
- if (IsCached) {
- MemoryStream ms = output_stream.GetData ();
- cached_response.ContentLength = (int) ms.Length;
- cached_response.SetData (ms.GetBuffer ());
- }
+ if (IsCached)
+ cached_response.SetData (output_stream.GetData ());
if (WorkerRequest != null)
output_stream.Flush (WorkerRequest, final_flush);
AppendHeader ("PICS-Label", value);
}
- public void Redirect (string url)
- {
- Redirect (url, true);
- }
-
- public void Redirect (string url, bool endResponse)
+ void Redirect (string url, bool endResponse, int code)
{
+ if (url == null)
+ throw new ArgumentNullException ("url");
+
if (headers_sent)
throw new HttpException ("Headers have already been sent");
-#if NET_2_0
+ if (url.IndexOf ('\n') != -1)
+ throw new ArgumentException ("Redirect URI cannot contain newline characters.", "url");
+
is_request_being_redirected = true;
-#endif
ClearHeaders ();
ClearContent ();
- StatusCode = 302;
+ StatusCode = code;
url = ApplyAppPathModifier (url);
+
+ bool isFullyQualified;
+ if (StrUtils.StartsWith (url, "http:", true) ||
+ StrUtils.StartsWith (url, "https:", true) ||
+ StrUtils.StartsWith (url, "file:", true) ||
+ StrUtils.StartsWith (url, "ftp:", true))
+ isFullyQualified = true;
+ else
+ isFullyQualified = false;
+
+ if (!isFullyQualified) {
+ HttpRuntimeSection config = HttpRuntime.Section;
+ if (config != null && config.UseFullyQualifiedRedirectUrl) {
+ var ub = new UriBuilder (context.Request.Url);
+ int qpos = url.IndexOf ('?');
+ if (qpos == -1) {
+ ub.Path = url;
+ ub.Query = null;
+ } else {
+ ub.Path = url.Substring (0, qpos);
+ ub.Query = url.Substring (qpos + 1);
+ }
+ ub.Fragment = null;
+ ub.Password = null;
+ ub.UserName = null;
+ url = ub.Uri.ToString ();
+ }
+ }
+
redirect_location = url;
// Text for browsers that can't handle location header
if (endResponse)
End ();
-#if NET_2_0
is_request_being_redirected = false;
-#endif
}
+
+ public void Redirect (string url)
+ {
+ Redirect (url, true);
+ }
+
+ public void Redirect (string url, bool endResponse)
+ {
+ Redirect (url, endResponse, 302);
+ }
+#if NET_4_0
+ public void RedirectPermanent (string url)
+ {
+ RedirectPermanent (url, true);
+ }
+
+ public void RedirectPermanent (string url, bool endResponse)
+ {
+ Redirect (url, endResponse, 301);
+ }
+
+ public void RedirectToRoute (object routeValues)
+ {
+ RedirectToRoute ("RedirectToRoute", null, new RouteValueDictionary (routeValues), 302, true);
+ }
+
+ public void RedirectToRoute (RouteValueDictionary routeValues)
+ {
+ RedirectToRoute ("RedirectToRoute", null, routeValues, 302, true);
+ }
+
+ public void RedirectToRoute (string routeName)
+ {
+ RedirectToRoute ("RedirectToRoute", routeName, null, 302, true);
+ }
+
+ public void RedirectToRoute (string routeName, object routeValues)
+ {
+ RedirectToRoute ("RedirectToRoute", routeName, new RouteValueDictionary (routeValues), 302, true);
+ }
+
+ public void RedirectToRoute (string routeName, RouteValueDictionary routeValues)
+ {
+ RedirectToRoute ("RedirectToRoute", routeName, routeValues, 302, true);
+ }
+
+ public void RedirectToRoutePermanent (object routeValues)
+ {
+ RedirectToRoute ("RedirectToRoutePermanent", null, new RouteValueDictionary (routeValues), 301, false);
+ }
+
+ public void RedirectToRoutePermanent (RouteValueDictionary routeValues)
+ {
+ RedirectToRoute ("RedirectToRoutePermanent", null, routeValues, 301, false);
+ }
+
+ public void RedirectToRoutePermanent (string routeName)
+ {
+ RedirectToRoute ("RedirectToRoutePermanent", routeName, null, 301, false);
+ }
+
+ public void RedirectToRoutePermanent (string routeName, object routeValues)
+ {
+ RedirectToRoute ("RedirectToRoutePermanent", routeName, new RouteValueDictionary (routeValues), 301, false);
+ }
+
+ public void RedirectToRoutePermanent (string routeName, RouteValueDictionary routeValues)
+ {
+ RedirectToRoute ("RedirectToRoutePermanent", routeName, routeValues, 301, false);
+ }
+
+ void RedirectToRoute (string callerName, string routeName, RouteValueDictionary routeValues, int redirectCode, bool endResponse)
+ {
+ HttpContext ctx = context ?? HttpContext.Current;
+ HttpRequest req = ctx != null ? ctx.Request : null;
+
+ if (req == null)
+ // Let's emulate .NET
+ throw new NullReferenceException ();
+
+ VirtualPathData vpd = RouteTable.Routes.GetVirtualPath (req.RequestContext, routeName, routeValues);
+ string redirectUrl = vpd != null ? vpd.VirtualPath : null;
+ if (String.IsNullOrEmpty (redirectUrl))
+ throw new InvalidOperationException ("No matching route found for RedirectToRoute");
+ Redirect (redirectUrl, true, redirectCode);
+ }
+
+ public static void RemoveOutputCacheItem (string path, string providerName)
+ {
+ if (path == null)
+ throw new ArgumentNullException ("path");
+
+ if (path.Length > 0 && path [0] != '/')
+ throw new ArgumentException ("Invalid path for HttpResponse.RemoveOutputCacheItem: '" + path + "'. An absolute virtual path is expected");
+
+ OutputCache.RemoveFromProvider (path, providerName);
+ }
+#endif
public static void RemoveOutputCacheItem (string path)
{
if (path == null)
if (path [0] != '/')
throw new ArgumentException ("'" + path + "' is not an absolute virtual path.");
- HttpRuntime.InternalCache.Remove (path);
+#if NET_4_0
+ RemoveOutputCacheItem (path, OutputCache.DefaultProviderName);
+#else
+ HttpContext context = HttpContext.Current;
+ HttpApplication app_instance = context != null ? context.ApplicationInstance : null;
+ HttpModuleCollection modules = app_instance != null ? app_instance.Modules : null;
+ OutputCacheModule ocm = modules != null ? modules.Get ("OutputCache") as OutputCacheModule : null;
+ OutputCacheProvider internalProvider = ocm != null ? ocm.InternalProvider : null;
+ if (internalProvider == null)
+ return;
+
+ internalProvider.Remove (path);
+#endif
}
public void SetCookie (HttpCookie cookie)
public void Write (char ch)
{
- Output.Write (ch);
+ TextWriter writer = Output;
+#if NET_4_0
+ // Emulating .NET
+ if (writer == null)
+ throw new NullReferenceException (".NET 4.0 emulation. A null value was found where an object was required.");
+#endif
+ writer.Write (ch);
}
public void Write (object obj)
{
+ TextWriter writer = Output;
+#if NET_4_0
+ // Emulating .NET
+ if (writer == null)
+ throw new NullReferenceException (".NET 4.0 emulation. A null value was found where an object was required.");
+#endif
if (obj == null)
return;
- Output.Write (obj.ToString ());
+ writer.Write (obj.ToString ());
}
public void Write (string s)
{
- Output.Write (s);
+ TextWriter writer = Output;
+#if NET_4_0
+ // Emulating .NET
+ if (writer == null)
+ throw new NullReferenceException (".NET 4.0 emulation. A null value was found where an object was required.");
+#endif
+ writer.Write (s);
}
public void Write (char [] buffer, int index, int count)
{
- Output.Write (buffer, index, count);
+ TextWriter writer = Output;
+#if NET_4_0
+ // Emulating .NET
+ if (writer == null)
+ throw new NullReferenceException (".NET 4.0 emulation. A null value was found where an object was required.");
+#endif
+ writer.Write (buffer, index, count);
}
+ bool IsFileSystemDirSeparator (char ch)
+ {
+ return ch == '\\' || ch == '/';
+ }
+
+ string GetNormalizedFileName (string fn)
+ {
+ if (String.IsNullOrEmpty (fn))
+ return fn;
+
+ // On Linux we don't change \ to / since filenames with \ are valid. We also
+ // don't remove drive: designator for the same reason.
+ int len = fn.Length;
+ if (len >= 3 && fn [1] == ':' && IsFileSystemDirSeparator (fn [2]))
+ return Path.GetFullPath (fn); // drive-qualified absolute file path
+
+ bool startsWithDirSeparator = IsFileSystemDirSeparator (fn [0]);
+ if (len >= 2 && startsWithDirSeparator && IsFileSystemDirSeparator (fn [1]))
+ return Path.GetFullPath (fn); // UNC path
+
+ if (!startsWithDirSeparator) {
+ HttpContext ctx = context ?? HttpContext.Current;
+ HttpRequest req = ctx != null ? ctx.Request : null;
+
+ if (req != null)
+ return req.MapPath (fn);
+ }
+
+ return fn; // Or should we rather throw?
+ }
+
internal void WriteFile (FileStream fs, long offset, long size)
{
byte [] buffer = new byte [32*1024];
if (filename == null)
throw new ArgumentNullException ("filename");
+ string fn = GetNormalizedFileName (filename);
if (readIntoMemory){
- using (FileStream fs = File.OpenRead (filename))
+ using (FileStream fs = File.OpenRead (fn))
WriteFile (fs, 0, fs.Length);
} else {
- FileInfo fi = new FileInfo (filename);
- output_stream.WriteFile (filename, 0, fi.Length);
+ FileInfo fi = new FileInfo (fn);
+ output_stream.WriteFile (fn, 0, fi.Length);
}
if (buffer)
return;
output_stream.ApplyFilter (false);
Flush ();
}
-#if NET_2_0
- [MonoTODO ("Not implemented")]
+
public void WriteSubstitution (HttpResponseSubstitutionCallback callback)
{
- throw new NotImplementedException ();
+ // Emulation of .NET behavior
+ if (callback == null)
+ throw new NullReferenceException ();
+
+ object target = callback.Target;
+ if (target != null && target.GetType () == typeof (Control))
+ throw new ArgumentException ("callback");
+
+ string s = callback (context);
+ if (!IsCached) {
+ Write (s);
+ return;
+ }
+
+ Cache.Cacheability = HttpCacheability.Server;
+ Flush ();
+ if (WorkerRequest == null)
+ Write (s); // better this than nothing
+ else {
+ byte[] bytes = WebEncoding.ResponseEncoding.GetBytes (s);
+ WorkerRequest.SendResponseFromMemory (bytes, bytes.Length);
+ }
+
+ cached_response.SetData (callback);
}
-#endif
+
//
// Like WriteFile, but never buffers, so we manually Flush here
//
Flush (final_flush);
}
-#if NET_2_0
public void TransmitFile (string filename, long offset, long length)
{
output_stream.WriteFile (filename, offset, length);
Flush (true);
}
}
-#endif
#region Session state support
internal void SetAppPathModifier (string app_modifier)
#endregion
#region Cache Support
- internal void SetCachedHeaders (ArrayList headers)
+ internal void SetCachedHeaders (NameValueCollection headers)
{
cached_headers = headers;
+
}
internal bool IsCached {
if (value == null || value == "") {
Cache.SetCacheability (HttpCacheability.NoCache);
user_cache_control = null;
- } else if (String.Compare (value, "public", true, CultureInfo.InvariantCulture) == 0) {
+ } else if (String.Compare (value, "public", true, Helpers.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.Public);
user_cache_control = "public";
- } else if (String.Compare (value, "private", true, CultureInfo.InvariantCulture) == 0) {
+ } else if (String.Compare (value, "private", true, Helpers.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.Private);
user_cache_control = "private";
- } else if (String.Compare (value, "no-cache", true, CultureInfo.InvariantCulture) == 0) {
+ } else if (String.Compare (value, "no-cache", true, Helpers.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.NoCache);
user_cache_control = "no-cache";
} else
internal void ReleaseResources ()
{
- output_stream.ReleaseResources (true);
- output_stream = null;
+ if (output_stream != null)
+ output_stream.ReleaseResources (true);
+ if (completed)
+ return;
+
+ Close ();
+ completed = true;
}
}