-//
-// System.Web.HttpResponse
//
-// Authors:
-// Patrik Torstensson (Patrik.Torstensson@labs2.com)
-// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// System.Web.HttpResponse.cs
//
-// (c) 2002 Ximian, Inc. (http://www.ximian.com)
+//
+// Author:
+// Miguel de Icaza (miguel@novell.com)
+// Gonzalo Paniagua Javier (gonzalo@ximian.com)
+// Marek Habersack <mhabersack@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
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using System;
+
+using System.Text;
+using System.Web.UI;
using System.Collections;
-using System.Globalization;
+using System.Collections.Specialized;
using System.IO;
-using System.Text;
+using System.Web.Caching;
using System.Threading;
using System.Web.Util;
-using System.Web.Caching;
+using System.Web.Configuration;
+using System.Globalization;
+using System.Security.Permissions;
+using System.Web.Hosting;
+using System.Web.SessionState;
+
+#if NET_4_0
+using System.Web.Routing;
+#endif
namespace System.Web
-{
- public sealed class HttpResponse
+{
+ // CAS - no InheritanceDemand here as the class is sealed
+ [AspNetHostingPermission (SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
+ public sealed partial class HttpResponse
{
- // Chunked encoding static helpers
- static byte [] s_arrChunkSuffix = {13, 10};
- static byte [] s_arrChunkEnd = {48, 13, 10, 13, 10};
- static string s_sChunkedPrefix = "\r\n";
+ internal HttpWorkerRequest WorkerRequest;
+ internal HttpResponseStream output_stream;
+ internal bool buffer = true;
- ArrayList _Headers;
-
- bool _bClientDisconnected;
- bool _bSuppressHeaders;
- bool _bSuppressContent;
- bool _bChunked;
- bool _bEnded;
- bool _bBuffering;
- bool _bHeadersSent;
- bool _bFlushing;
- bool filtered;
- long _lContentLength;
- int _iStatusCode;
+ ArrayList fileDependencies;
- int _expiresInMinutes;
- bool _expiresInMinutesSet;
- DateTime _expiresAbsolute;
- bool _expiresAbsoluteSet;
+ HttpContext context;
+ TextWriter writer;
+ HttpCachePolicy cache_policy;
+ Encoding encoding;
+ HttpCookieCollection cookies;
+
+ int status_code = 200;
+ string status_description = "OK";
- bool _ClientDisconnected;
+ string content_type = "text/html";
+ string charset;
+ bool charset_set;
+ CachedRawResponse cached_response;
+ string user_cache_control = "private";
+ string redirect_location;
+ string version_header;
+ bool version_header_checked;
+
+ //
+ // Negative Content-Length means we auto-compute the size of content-length
+ // can be overwritten with AppendHeader ("Content-Length", value)
+ //
+ long content_length = -1;
+
+ //
+ // The list of the headers that we will send back to the client, except
+ // the headers that we compute here.
+ //
+
+ HttpHeaderCollection headers;
+ bool headers_sent;
+ NameValueCollection cached_headers;
+
+ //
+ // Transfer encoding state
+ //
+ string transfer_encoding;
+ internal bool use_chunked;
+
bool closed;
+ internal bool suppress_content;
- string _sContentType;
- string _sCacheControl;
- string _sTransferEncoding;
- string _sCharset;
- string _sStatusDescription;
- bool forced_charset;
-
- HttpCookieCollection _Cookies;
- HttpCachePolicy _CachePolicy;
-
- Encoding _ContentEncoding;
-
- HttpContext _Context;
- HttpWriter _Writer;
- TextWriter _TextWriter;
-
- HttpWorkerRequest _WorkerRequest;
+ //
+ // Session State
+ //
+ string app_path_mod;
+ bool is_request_being_redirected;
+ Encoding headerEncoding;
- ArrayList fileDependencies;
- CachedRawResponse cached_response;
- ArrayList cached_headers;
-#if NET_1_1
- string redirectLocation;
-#endif
-
- string app_path_mod = null;
-
- public HttpResponse (TextWriter output)
+ internal HttpResponse ()
{
- _bBuffering = true;
- _bFlushing = false;
- _bHeadersSent = false;
-
- _Headers = new ArrayList ();
-
- _sContentType = "text/html";
-
- _iStatusCode = 200;
- _sCharset = null;
- _sCacheControl = null;
-
- _lContentLength = 0;
- _bSuppressContent = false;
- _bSuppressHeaders = false;
- _bClientDisconnected = false;
-
- _bChunked = false;
-
- _TextWriter = output;
+ output_stream = new HttpResponseStream (this);
+ writer = new HttpWriter (this);
}
- internal HttpResponse (HttpWorkerRequest WorkerRequest, HttpContext Context)
+ public HttpResponse (TextWriter writer) : this ()
{
- _Context = Context;
- _WorkerRequest = WorkerRequest;
-
- _bBuffering = true;
- _bFlushing = false;
- _bHeadersSent = false;
-
- _Headers = new ArrayList ();
-
- _sContentType = "text/html";
-
- _iStatusCode = 200;
- _sCharset = null;
- _sCacheControl = null;
-
- _lContentLength = 0;
- _bSuppressContent = false;
- _bSuppressHeaders = false;
- _bClientDisconnected = false;
-
- _bChunked = false;
- }
- internal void InitializeWriter ()
- {
- // We cannot do this in the .ctor because HttpWriter uses configuration and
- // it may not be initialized
- if (_Writer == null) {
- _Writer = new HttpWriter (this);
- _TextWriter = _Writer;
- }
- }
-
- internal void FinalFlush ()
- {
- Flush (true);
+ this.writer = writer;
}
- internal void DoFilter (bool really)
+ internal HttpResponse (HttpWorkerRequest worker_request, HttpContext context) : this ()
{
- if (really && null != _Writer)
- _Writer.FilterData (true);
-
- filtered = true;
- }
+ WorkerRequest = worker_request;
+ this.context = context;
- internal bool IsCached {
- get { return cached_response != null; }
- }
-
- internal CachedRawResponse GetCachedResponse () {
- cached_response.StatusCode = StatusCode;
- cached_response.StatusDescription = StatusDescription;
- return cached_response;
+#if !TARGET_J2EE
+ if (worker_request != null)
+ use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
+#endif
+ writer = new HttpWriter (this);
}
- internal void SetCachedHeaders (ArrayList headers)
+ internal TextWriter SetTextWriter (TextWriter writer)
{
- cached_headers = headers;
+ TextWriter prev = this.writer;
+ this.writer = writer;
+ return prev;
}
-
- private ArrayList GenerateHeaders ()
- {
- ArrayList oHeaders = new ArrayList (_Headers.ToArray ());
-
- oHeaders.Add (new HttpResponseHeader ("X-Powered-By", "Mono"));
- // save culture info, we need us info here
- CultureInfo oSavedInfo = Thread.CurrentThread.CurrentCulture;
- Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
-
- string date = DateTime.UtcNow.ToString ("ddd, d MMM yyyy HH:mm:ss ");
- HttpResponseHeader date_header = new HttpResponseHeader ("Date", date + "GMT");
- oHeaders.Add (date_header);
-
- if (IsCached)
- cached_response.DateHeader = date_header;
-
- Thread.CurrentThread.CurrentCulture = oSavedInfo;
-
- if (_lContentLength > 0) {
- oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderContentLength,
- _lContentLength.ToString ()));
- }
- // Apache2 only auto-adds 'charset=blah' for text/plain and text/html
- if (_sContentType != null) {
- string ctype = _sContentType;
- if (forced_charset || _sContentType == "text/plain" || _sContentType == "text/html") {
- if (_sContentType.IndexOf ("charset=") == -1) {
- if (Charset.Length == 0)
- Charset = ContentEncoding.HeaderName;
-
- // Time to build our string
- if (Charset.Length > 0)
- ctype += "; charset=" + Charset;
- }
+ internal string VersionHeader {
+ get {
+ if (!version_header_checked && version_header == null) {
+ version_header_checked = true;
+ HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+ if (config != null && config.EnableVersionHeader)
+ version_header = Environment.Version.ToString (3);
}
- oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderContentType, ctype));
+ return version_header;
}
+ }
- if (_CachePolicy != null)
- _CachePolicy.SetHeaders (this, oHeaders);
+ internal HttpContext Context {
+ get { return context; }
+ set { context = value; }
+ }
- if (_sCacheControl != null) {
- oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderPragma,
- _sCacheControl));
- }
-
- if (_sTransferEncoding != null) {
- oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderTransferEncoding,
- _sTransferEncoding));
- }
-
- if (_Cookies != null) {
- int length = _Cookies.Count;
- for (int i = 0; i < length; i++) {
- oHeaders.Add (_Cookies.Get (i).GetCookieHeader ());
- }
+ internal string[] FileDependencies {
+ get {
+ if (fileDependencies == null || fileDependencies.Count == 0)
+ return new string[0] {};
+ return (string[]) fileDependencies.ToArray (typeof (string));
}
-#if NET_1_1
- if (redirectLocation != null)
- oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderLocation,
- redirectLocation));
-#endif
- return oHeaders;
}
- private void SendHeaders ()
- {
- _WorkerRequest.SendStatus (StatusCode, StatusDescription);
-
- ArrayList oHeaders;
-
- if (cached_headers != null)
- oHeaders = cached_headers;
- else
- oHeaders = GenerateHeaders ();
-
- if (cached_response != null)
- cached_response.SetHeaders (oHeaders);
-
- foreach (HttpResponseHeader oHeader in oHeaders)
- oHeader.SendContent (_WorkerRequest);
-
- _bHeadersSent = true;
+ ArrayList FileDependenciesArray {
+ get {
+ if (fileDependencies == null)
+ fileDependencies = new ArrayList ();
+ return fileDependencies;
+ }
}
-
- public string Status
- {
+
+ public bool Buffer {
get {
- return String.Format ("{0} {1}", StatusCode, StatusDescription);
+ return buffer;
}
set {
- string sMsg = "OK";
- int iCode = 200;
-
- try {
- iCode = Int32.Parse (value.Substring (0, value.IndexOf (' ')));
- sMsg = value.Substring (value.IndexOf (' ') + 1);
- } catch (Exception) {
- throw new HttpException ("Invalid status string");
- }
-
- StatusCode = iCode;
- StatusDescription = sMsg;
+ buffer = value;
}
}
- [MonoTODO()]
- public void AddCacheItemDependencies (ArrayList cacheKeys)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO()]
- public void AddCacheItemDependency(string cacheKey)
- {
- throw new NotImplementedException ();
- }
-
- public void AddFileDependencies (ArrayList filenames)
- {
- if (filenames == null || filenames.Count == 0)
- return;
-
- if (fileDependencies == null) {
- fileDependencies = (ArrayList) filenames.Clone ();
- return;
+ public bool BufferOutput {
+ get {
+ return buffer;
}
- foreach (string fn in filenames)
- AddFileDependency (fn);
- }
-
- public void AddFileDependency (string filename)
- {
- if (fileDependencies == null)
- fileDependencies = new ArrayList ();
-
- fileDependencies.Add (filename);
- }
-
- public void AddHeader (string name, string value)
- {
- AppendHeader(name, value);
- }
-
- public void AppendCookie (HttpCookie cookie)
- {
- if (_bHeadersSent)
- throw new HttpException ("Cannot append cookies after HTTP headers have been sent");
-
- Cookies.Add (cookie);
- }
-
- [MonoTODO()]
- public void AppendToLog (string param)
- {
- throw new NotImplementedException ();
+ set {
+ buffer = value;
+ }
}
- public string ApplyAppPathModifier (string virtualPath)
- {
- if (virtualPath == null)
- return null;
-
- if (virtualPath == "")
- return _Context.Request.RootVirtualDir;
-
- if (UrlUtils.IsRelativeUrl (virtualPath)) {
- virtualPath = UrlUtils.Combine (_Context.Request.RootVirtualDir, virtualPath);
- } else if (UrlUtils.IsRooted (virtualPath)) {
- virtualPath = UrlUtils.Reduce (virtualPath);
+ //
+ // Use the default from <globalization> section if the client has not set the encoding
+ //
+ public Encoding ContentEncoding {
+ get {
+ if (encoding == null) {
+ if (context != null) {
+ string client_content_type = context.Request.ContentType;
+ string parameter = HttpRequest.GetParameter (client_content_type, "; charset=");
+ if (parameter != null) {
+ try {
+ // Do what the #1 web server does
+ encoding = Encoding.GetEncoding (parameter);
+ } catch {
+ }
+ }
+ }
+ if (encoding == null)
+ encoding = WebEncoding.ResponseEncoding;
+ }
+ return encoding;
}
- if (app_path_mod != null && virtualPath.IndexOf (app_path_mod) < 0) {
- string rvd = _Context.Request.RootVirtualDir;
- string basevd = rvd.Replace (app_path_mod, "");
-
- if (!virtualPath.StartsWith (basevd))
- return virtualPath;
+ set {
+ if (value == null)
+ throw new ArgumentException ("ContentEncoding can not be null");
- virtualPath = UrlUtils.Combine (rvd, virtualPath.Substring (basevd.Length));
+ encoding = value;
+ HttpWriter http_writer = writer as HttpWriter;
+ if (http_writer != null)
+ http_writer.SetEncoding (encoding);
}
-
- return virtualPath;
- }
-
- internal void SetAppPathModifier (string app_path_mod)
- {
- this.app_path_mod = app_path_mod;
}
- public bool Buffer
- {
+ public string ContentType {
get {
- return BufferOutput;
+ return content_type;
}
set {
- BufferOutput = value;
+ content_type = value;
}
}
- public bool BufferOutput
- {
+ public string Charset {
get {
- return _bBuffering;
+ if (charset == null)
+ charset = ContentEncoding.WebName;
+
+ return charset;
}
-
- set {
- if (_Writer != null)
- _Writer.Update ();
- _bBuffering = value;
+ set {
+ charset_set = true;
+ charset = value;
}
}
-
- public HttpCachePolicy Cache
- {
+
+ public HttpCookieCollection Cookies {
get {
- if (null == _CachePolicy) {
- _CachePolicy = new HttpCachePolicy ();
- _CachePolicy.CacheabilityUpdated += new CacheabilityUpdatedCallback (
- OnCacheabilityUpdated);
- }
-
- return _CachePolicy;
+ if (cookies == null)
+ cookies = new HttpCookieCollection (true, false);
+ return cookies;
}
}
-
- private void OnCacheabilityUpdated (object sender, CacheabilityUpdatedEventArgs e)
- {
- if (e.Cacheability >= HttpCacheability.Server && !IsCached)
- cached_response = new CachedRawResponse (_CachePolicy);
- else if (e.Cacheability <= HttpCacheability.Private)
- cached_response = null;
- }
- [MonoTODO("Set status in the cache policy")]
- public string CacheControl
- {
+ public int Expires {
get {
- return _sCacheControl;
+ if (cache_policy == null)
+ return 0;
+
+ return cache_policy.ExpireMinutes ();
}
set {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- _sCacheControl = value;
+ Cache.SetExpires (DateTime.Now + new TimeSpan (0, value, 0));
}
}
-
- public string Charset
- {
+
+ public DateTime ExpiresAbsolute {
get {
- if (null == _sCharset)
- _sCharset = ContentEncoding.WebName;
-
- return _sCharset;
+ return Cache.Expires;
}
set {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- if (value == null)
- value = "";
-
- forced_charset = true;
- _sCharset = value;
+ Cache.SetExpires (value);
}
}
- public Encoding ContentEncoding
- {
+ public Stream Filter {
get {
- if (_ContentEncoding == null)
- _ContentEncoding = WebEncoding.ResponseEncoding;
+ if (WorkerRequest == null)
+ return null;
- return _ContentEncoding;
+ return output_stream.Filter;
}
set {
- if (value == null)
- throw new ArgumentNullException ("Can't set a null as encoding");
-
- _ContentEncoding = value;
-
- if (_Writer != null)
- _Writer.Update ();
+ output_stream.Filter = value;
}
}
- public string ContentType
- {
+ public Encoding HeaderEncoding {
get {
- return _sContentType;
+ if (headerEncoding == null) {
+ GlobalizationSection gs = WebConfigurationManager.SafeGetSection ("system.web/globalization", typeof (GlobalizationSection)) as GlobalizationSection;
+
+ if (gs == null)
+ headerEncoding = Encoding.UTF8;
+ else {
+ headerEncoding = gs.ResponseHeaderEncoding;
+ if (headerEncoding == Encoding.Unicode)
+ throw new HttpException ("HeaderEncoding must not be Unicode");
+ }
+ }
+ return headerEncoding;
}
-
set {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- _sContentType = value;
+ if (headers_sent)
+ throw new HttpException ("headers have already been sent");
+ if (value == null)
+ throw new ArgumentNullException ("HeaderEncoding");
+ if (value == Encoding.Unicode)
+ throw new HttpException ("HeaderEncoding must not be Unicode");
+ headerEncoding = value;
}
}
- public HttpCookieCollection Cookies
- {
+ public NameValueCollection Headers {
get {
- if (null == _Cookies)
- _Cookies = new HttpCookieCollection (this, false);
+ if (headers == null)
+ headers = new HttpHeaderCollection ();
- return _Cookies;
+ return headers;
}
}
- public int Expires
- {
+
+ public bool IsClientConnected {
get {
- return _expiresInMinutes;
- }
+ if (WorkerRequest == null)
+ return true; // yep that's true
- set {
- if (!_expiresInMinutesSet || (value < _expiresInMinutes))
- {
- _expiresInMinutes = value;
- Cache.SetExpires(_Context.Timestamp.Add(new TimeSpan(0, _expiresInMinutes, 0)));
- }
- _expiresInMinutesSet = true;
+ return WorkerRequest.IsClientConnected ();
}
}
- public DateTime ExpiresAbsolute
- {
+ public bool IsRequestBeingRedirected {
+ get { return is_request_being_redirected; }
+ }
+
+ public TextWriter Output {
get {
- return _expiresAbsolute;
+ return writer;
}
+#if NET_4_0
+ set { writer = value; }
+#endif
+ }
- set {
- if (!_expiresAbsoluteSet || value.CompareTo(_expiresAbsolute)<0)
- {
- _expiresAbsolute = value;
- Cache.SetExpires(_expiresAbsolute);
- }
- _expiresAbsoluteSet = true;
+ public Stream OutputStream {
+ get {
+ return output_stream;
}
}
-
- public Stream Filter
- {
+
+ public string RedirectLocation {
get {
- if (_Writer != null)
- return _Writer.GetActiveFilter ();
-
- return null;
+ return redirect_location;
}
set {
- if (_Writer == null)
- throw new HttpException ("Filtering is not allowed");
-
- _Writer.ActivateFilter (value);
+ redirect_location = value;
}
}
+
+ public string Status {
+ get { return String.Concat (status_code.ToString (), " ", StatusDescription); }
- public bool IsClientConnected
- {
- get {
- if (_ClientDisconnected)
- return false;
-
- if (null != _WorkerRequest && (!_WorkerRequest.IsClientConnected ())) {
- _ClientDisconnected = false;
- return false;
- }
-
- return true;
- }
- }
-
- public TextWriter Output
- {
- get {
- return _TextWriter;
+ set {
+ int p = value.IndexOf (' ');
+ if (p == -1)
+ throw new HttpException ("Invalid format for the Status property");
+
+ string s = value.Substring (0, p);
+
+ if (!Int32.TryParse (s, out status_code))
+ throw new HttpException ("Invalid format for the Status property");
+
+ status_description = value.Substring (p+1);
}
}
- public Stream OutputStream
- {
- get {
- if (_Writer == null)
- throw new HttpException ("an Output stream not available when " +
- "running with custom text writer");
-
- return _Writer.OutputStream;
- }
+ // 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;
}
-#if NET_1_1
- public string RedirectLocation {
- get { return redirectLocation; }
- set { redirectLocation = value; }
+ public bool TrySkipIisCustomErrors {
+ get;
+ set;
}
-#endif
- public string StatusDescription
- {
+ public int StatusCode {
get {
- if (null == _sStatusDescription)
- _sStatusDescription =
- HttpWorkerRequest.GetStatusDescription (_iStatusCode);
-
- return _sStatusDescription;
+ return status_code;
}
set {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- _sStatusDescription = value;
+ if (headers_sent)
+ throw new HttpException ("headers have already been sent");
+
+ status_code = value;
+ status_description = null;
}
}
-
- public int StatusCode
- {
+
+ public string StatusDescription {
get {
- return _iStatusCode;
+ if (status_description == null)
+ status_description = HttpWorkerRequest.GetStatusDescription (status_code);
+
+ return status_description;
}
set {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- _sStatusDescription = null;
- _iStatusCode = value;
+ if (headers_sent)
+ throw new HttpException ("headers have already been sent");
+
+ status_description = value;
}
}
-
- public bool SuppressContent
- {
+
+ public bool SuppressContent {
get {
- return _bSuppressContent;
+ return suppress_content;
}
-
+
set {
- _bSuppressContent = true;
+ suppress_content = value;
}
}
- HttpRequest Request
+ [MonoTODO ("Not implemented")]
+ public void AddCacheDependency (CacheDependency[] dependencies)
{
- get {
- if (_Context == null)
- return null;
-
- return _Context.Request;
- }
+ throw new NotImplementedException ();
}
- internal void AppendHeader (int iIndex, string value)
- {
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- switch (iIndex) {
- case HttpWorkerRequest.HeaderContentLength:
- _lContentLength = Int64.Parse (value);
- break;
- case HttpWorkerRequest.HeaderContentEncoding:
- _sContentType = value;
- break;
- case HttpWorkerRequest.HeaderTransferEncoding:
- _sTransferEncoding = value;
- _bChunked = (value == "chunked");
- break;
- case HttpWorkerRequest.HeaderPragma:
- _sCacheControl = value;
- break;
- default:
- _Headers.Add (new HttpResponseHeader (iIndex, value));
- break;
- }
+ [MonoTODO ("Not implemented")]
+ public void AddCacheItemDependencies (string[] cacheKeys)
+ {
+ throw new NotImplementedException ();
}
- public void AppendHeader (string name, string value)
+ [MonoTODO("Currently does nothing")]
+ public void AddCacheItemDependencies (ArrayList cacheKeys)
{
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
-
- switch (name.ToLower ()) {
- case "content-length":
- _lContentLength = Int64.Parse (value);
- break;
- case "content-type":
- _sContentType = value;
- break;
- case "transfer-encoding":
- _sTransferEncoding = value;
- _bChunked = (value == "chunked");
- break;
- case "pragma":
- _sCacheControl = value;
- break;
- default:
- _Headers.Add (new HttpResponseHeader (name, value));
- break;
- }
+ // TODO: talk to jackson about the cache
}
-
- internal TextWriter SetTextWriter (TextWriter w)
+
+ [MonoTODO("Currently does nothing")]
+ public void AddCacheItemDependency (string cacheKey)
{
- TextWriter prev = _TextWriter;
- _TextWriter = w;
- return prev;
+ // TODO: talk to jackson about the cache
}
- public void BinaryWrite (byte [] buffer)
+ public void AddFileDependencies (ArrayList filenames)
{
- OutputStream.Write (buffer, 0, buffer.Length);
+ if (filenames == null || filenames.Count == 0)
+ return;
+ FileDependenciesArray.AddRange (filenames);
}
- internal void BinaryWrite (byte [] buffer, int start, int length)
- {
- OutputStream.Write (buffer, start, length);
- }
-
- public void Clear ()
+ public void AddFileDependencies (string[] filenames)
{
- if (_Writer != null)
- _Writer.Clear ();
+ if (filenames == null || filenames.Length == 0)
+ return;
+ FileDependenciesArray.AddRange (filenames);
}
- public void ClearContent ()
+ public void AddFileDependency (string filename)
{
- Clear();
+ if (filename == null || filename == String.Empty)
+ return;
+ FileDependenciesArray.Add (filename);
}
- internal void SetHeadersSent (bool val)
+ public void AddHeader (string name, string value)
{
- _bHeadersSent = val;
+ AppendHeader (name, value);
}
-
- public void ClearHeaders ()
+
+ public void AppendCookie (HttpCookie cookie)
{
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
+ Cookies.Add (cookie);
+ }
- _sContentType = "text/html";
- forced_charset = false;
+ //
+ // AppendHeader:
+ // Special case for Content-Length, Content-Type, Transfer-Encoding and Cache-Control
+ //
+ //
+ public void AppendHeader (string name, string value)
+ {
+ if (headers_sent)
+ throw new HttpException ("Headers have been already sent");
+#if !TARGET_J2EE
+ if (String.Compare (name, "content-length", true, Helpers.InvariantCulture) == 0){
+ content_length = (long) UInt64.Parse (value);
+ use_chunked = false;
+ return;
+ }
+#endif
- _iStatusCode = 200;
- _sCharset = null;
- _Headers = new ArrayList ();
- _sCacheControl = null;
- _sTransferEncoding = null;
+ if (String.Compare (name, "content-type", true, Helpers.InvariantCulture) == 0){
+ ContentType = value;
+ return;
+ }
- _lContentLength = 0;
- _bSuppressContent = false;
- _bSuppressHeaders = false;
- _bClientDisconnected = false;
- }
+#if !TARGET_J2EE
+ if (String.Compare (name, "transfer-encoding", true, Helpers.InvariantCulture) == 0){
+ transfer_encoding = value;
+ use_chunked = false;
+ return;
+ }
+#endif
- public void Close ()
- {
- if (closed && !_bClientDisconnected) {
- _bClientDisconnected = false;
- _WorkerRequest.CloseConnection ();
- _bClientDisconnected = true;
+ if (String.Compare (name, "cache-control", true, Helpers.InvariantCulture) == 0){
+ user_cache_control = value;
+ return;
}
+
+ Headers.Add (name, value);
}
- internal void Dispose ()
+ [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Medium)]
+ public void AppendToLog (string param)
+ {
+ Console.Write ("System.Web: ");
+ Console.WriteLine (param);
+ }
+
+ public string ApplyAppPathModifier (string virtualPath)
{
- if (_Writer != null) {
- _Writer.Dispose ();
- _Writer = null;
+ if (virtualPath == null || context == null)
+ return null;
+
+ if (virtualPath.Length == 0)
+ return context.Request.RootVirtualDir;
+
+ if (UrlUtils.IsRelativeUrl (virtualPath)) {
+ virtualPath = UrlUtils.Combine (context.Request.RootVirtualDir, virtualPath);
+ } else if (UrlUtils.IsRooted (virtualPath)) {
+ virtualPath = UrlUtils.Canonic (virtualPath);
+ }
+
+ bool cookieless = false;
+ SessionStateSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/sessionState") as SessionStateSection;
+ cookieless = SessionStateModule.IsCookieLess (context, config);
+
+ if (!cookieless)
+ return virtualPath;
+
+ if (app_path_mod != null && virtualPath.IndexOf (app_path_mod) < 0) {
+ if (UrlUtils.HasSessionId (virtualPath))
+ virtualPath = UrlUtils.RemoveSessionId (VirtualPathUtility.GetDirectory (virtualPath), virtualPath);
+ return UrlUtils.InsertSessionId (app_path_mod, virtualPath);
}
+
+ return virtualPath;
}
- [MonoTODO("Handle callbacks into before done with session, needs to have a non ended flush here")]
- internal void FlushAtEndOfRequest ()
+ public void BinaryWrite (byte [] buffer)
{
- Flush (true);
+ output_stream.Write (buffer, 0, buffer.Length);
}
- public void End ()
+ internal void BinaryWrite (byte [] buffer, int start, int len)
{
- if (_bEnded)
- return;
+ output_stream.Write (buffer, start, len);
+ }
- if (_Context.TimeoutPossible)
- Thread.CurrentThread.Abort (new StepCompleteRequest ());
+ public void Clear ()
+ {
+ ClearContent ();
+ }
- Flush ();
- _bEnded = true;
- _Context.ApplicationInstance.CompleteRequest ();
+ public void ClearContent ()
+ {
+ output_stream.Clear ();
+ content_length = -1;
}
- public void Flush ()
+ public void ClearHeaders ()
{
- if (closed)
- throw new HttpException ("Response already finished.");
+ if (headers_sent)
+ throw new HttpException ("headers have been already sent");
- Flush (false);
+ // Reset the special case headers.
+ content_length = -1;
+ content_type = "text/html";
+ transfer_encoding = null;
+ user_cache_control = "private";
+ if (cache_policy != null)
+ cache_policy.Cacheability = HttpCacheability.Private;
+
+ if (headers != null)
+ headers.Clear ();
}
- private void Flush (bool bFinish)
+ internal bool HeadersSent {
+ get {
+ return headers_sent;
+ }
+ }
+
+ public void Close ()
{
- if (_bFlushing || closed)
+ if (closed)
return;
+ if (WorkerRequest != null)
+ WorkerRequest.CloseConnection ();
+ closed = true;
+ }
- _bFlushing = true;
-
- if (_Writer == null) {
- _TextWriter.Flush ();
- _bFlushing = false;
+ public void DisableKernelCache ()
+ {
+ // does nothing in Mono
+ }
+
+ public void End ()
+ {
+ if (context == null)
return;
+
+ if (context.TimeoutPossible) {
+ Thread.CurrentThread.Abort (FlagEnd.Value);
+ } else {
+ // If this is called from an async event, signal the completion
+ // but don't throw.
+ HttpApplication app_instance = context.ApplicationInstance;
+ if (app_instance != null)
+ app_instance.CompleteRequest ();
}
+ }
- try {
- if (_bClientDisconnected)
- return;
-
- long length = _Writer.BufferSize;
- if (!_bHeadersSent && !_bSuppressHeaders) {
- if (bFinish) {
- if (length == 0 && _lContentLength == 0)
- _sContentType = null;
-
- SendHeaders ();
- length = _Writer.BufferSize;
- _WorkerRequest.SendCalculatedContentLength ((int) length);
- } else {
- if (_lContentLength == 0 && _iStatusCode == 200 &&
- _sTransferEncoding == null) {
- // Check we are going todo chunked encoding
- string sProto = Request.ServerVariables ["SERVER_PROTOCOL"];
- if (sProto != null && sProto == "HTTP/1.1") {
- AppendHeader (
- HttpWorkerRequest.HeaderTransferEncoding,
- "chunked");
- } else {
- // Just in case, the old browsers send a HTTP/1.0
- // request with Connection: Keep-Alive
- AppendHeader (
- HttpWorkerRequest.HeaderConnection,
- "Close");
- }
- }
-
- length = _Writer.BufferSize;
- SendHeaders ();
+ // Generate:
+ // Content-Length
+ // Content-Type
+ // Transfer-Encoding (chunked)
+ // Cache-Control
+ // X-AspNet-Version
+ void AddHeadersNoCache (NameValueCollection write_headers, bool final_flush)
+ {
+#if !TARGET_J2EE
+ //
+ // Transfer-Encoding
+ //
+ if (use_chunked)
+ write_headers.Add ("Transfer-Encoding", "chunked");
+ else if (transfer_encoding != null)
+ write_headers.Add ("Transfer-Encoding", transfer_encoding);
+#endif
+ if (redirect_location != null)
+ write_headers.Add ("Location", redirect_location);
+
+#if !TARGET_J2EE
+ 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 (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderContentLength),
+ content_length.ToString (Helpers.InvariantCulture));
+ } else if (BufferOutput) {
+ if (final_flush) {
+ //
+ // If we are buffering and this is the last flush, not a middle-flush,
+ // we know the content-length.
+ //
+ content_length = output_stream.total;
+ 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 (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderConnection), "close");
}
}
-
- if (!filtered) {
- _Writer.FilterData (false);
- length = _Writer.BufferSize;
+ } else {
+ //
+ // If the content-length is not set, and we are not buffering, we must
+ // close at the end.
+ //
+ if (use_chunked){
+ write_headers.Add (HttpWorkerRequest.GetKnownResponseHeaderName (HttpWorkerRequest.HeaderConnection), "close");
}
+ }
+#endif
- if (length == 0) {
- if (bFinish && _bChunked) {
- _WorkerRequest.SendResponseFromMemory (s_arrChunkEnd,
- s_arrChunkEnd.Length);
+ //
+ // Cache Control, the cache policy takes precedence over the cache_control property.
+ //
+ if (cache_policy != null)
+ cache_policy.SetHeaders (this, headers);
+ else
+ write_headers.Add ("Cache-Control", CacheControl);
+
+ //
+ // Content-Type
+ //
+ if (content_type != null){
+ string header = content_type;
+
+ if (charset_set || header == "text/plain" || header == "text/html") {
+ if (header.IndexOf ("charset=") == -1) {
+ if (charset == null || charset == "")
+ charset = ContentEncoding.HeaderName;
+ header += "; charset=" + charset;
}
-
- _WorkerRequest.FlushResponse (bFinish);
- if (!bFinish)
- _Writer.Clear ();
- return;
}
+
+ write_headers.Add ("Content-Type", header);
+ }
- if (!_bSuppressContent && Request.HttpMethod == "HEAD")
- _bSuppressContent = true;
-
- if (_bSuppressContent)
- _Writer.Clear ();
+ if (cookies != null && cookies.Count != 0){
+ int n = cookies.Count;
+ for (int i = 0; i < n; i++)
+ 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);
+#endif
+ }
+ }
- if (!_bSuppressContent) {
- _bClientDisconnected = false;
- if (_bChunked) {
- Encoding oASCII = Encoding.ASCII;
+ internal void WriteHeaders (bool final_flush)
+ {
+ if (headers_sent)
+ return;
- string chunk = Convert.ToString(_Writer.BufferSize, 16);
- byte [] arrPrefix = oASCII.GetBytes (chunk + s_sChunkedPrefix);
+ //
+ // Flush
+ //
+ if (context != null) {
+ HttpApplication app_instance = context.ApplicationInstance;
+ if (app_instance != null)
+ app_instance.TriggerPreSendRequestHeaders ();
+ }
- _WorkerRequest.SendResponseFromMemory (arrPrefix,
- arrPrefix.Length);
+ headers_sent = true;
- _Writer.SendContent (_WorkerRequest);
+ if (cached_response != null)
+ cached_response.SetHeaders (headers);
- _WorkerRequest.SendResponseFromMemory (s_arrChunkSuffix,
- s_arrChunkSuffix.Length);
- if (bFinish)
- _WorkerRequest.SendResponseFromMemory (
- s_arrChunkEnd, s_arrChunkEnd.Length);
- } else {
- _Writer.SendContent (_WorkerRequest);
+ // If this page is cached use the cached headers
+ // instead of the standard headers
+ NameValueCollection write_headers;
+ if (cached_headers != null)
+ write_headers = cached_headers;
+ else {
+ write_headers = Headers;
+ AddHeadersNoCache (write_headers, final_flush);
+ }
+
+ if (WorkerRequest != null)
+ WorkerRequest.SendStatus (status_code, StatusDescription);
+
+ if (WorkerRequest != null) {
+ 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);
}
}
-
- _WorkerRequest.FlushResponse (bFinish);
- if (IsCached) {
- cached_response.ContentLength = (int) length;
- cached_response.SetData (_Writer.GetBuffer ());
- }
- _Writer.Clear ();
- } finally {
- if (bFinish)
- closed = true;
- _bFlushing = false;
}
}
- public void Pics (string value)
+ internal void DoFilter (bool close)
{
- AppendHeader ("PICS-Label", value);
+ if (output_stream.HaveFilter && context != null && context.Error == null)
+ output_stream.ApplyFilter (close);
}
+ internal void Flush (bool final_flush)
+ {
+ DoFilter (final_flush);
+ if (!headers_sent){
+ if (final_flush || status_code != 200)
+ use_chunked = false;
+ }
- public void Redirect (string url)
+ bool head = ((context != null) && (context.Request.HttpMethod == "HEAD"));
+ if (suppress_content || head) {
+ if (!headers_sent)
+ WriteHeaders (true);
+ output_stream.Clear ();
+ if (WorkerRequest != null)
+ output_stream.Flush (WorkerRequest, true); // ignore final_flush here.
+ return;
+ }
+
+ if (!headers_sent)
+ WriteHeaders (final_flush);
+
+ if (context != null) {
+ HttpApplication app_instance = context.ApplicationInstance;
+ if (app_instance != null)
+ app_instance.TriggerPreSendRequestContent ();
+ }
+
+ if (IsCached)
+ cached_response.SetData (output_stream.GetData ());
+
+ if (WorkerRequest != null)
+ output_stream.Flush (WorkerRequest, final_flush);
+ }
+
+ public void Flush ()
{
- Redirect (url, true);
+ Flush (false);
}
- public void Redirect (string url, bool endResponse)
+ public void Pics (string value)
{
- if (_bHeadersSent)
- throw new HttpException ("Headers has been sent to the client");
+ AppendHeader ("PICS-Label", value);
+ }
- Clear ();
+ 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 (url.IndexOf ('\n') != -1)
+ throw new ArgumentException ("Redirect URI cannot contain newline characters.", "url");
+
+ is_request_being_redirected = true;
+ ClearHeaders ();
+ ClearContent ();
+
+ StatusCode = code;
url = ApplyAppPathModifier (url);
- StatusCode = 302;
- AppendHeader (HttpWorkerRequest.HeaderLocation, 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 = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+ if (config != null && config.UseFullyQualifiedRedirectUrl) {
+ var ub = new UriBuilder (context.Request.Url);
+ ub.Path = url;
+ ub.Fragment = null;
+ ub.Password = null;
+ ub.Query = null;
+ ub.UserName = null;
+ url = ub.Uri.ToString ();
+ }
+ }
+
+ redirect_location = url;
// Text for browsers that can't handle location header
Write ("<html><head><title>Object moved</title></head><body>\r\n");
- Write ("<h2>Object moved to <a href='" + url + "'>here</a></h2>\r\n");
+ Write ("<h2>Object moved to <a href=\"" + url + "\">here</a></h2>\r\n");
Write ("</body><html>\r\n");
-
+
if (endResponse)
End ();
+ is_request_being_redirected = false;
+ }
+
+ public void Redirect (string url)
+ {
+ Redirect (url, true);
}
- internal bool RedirectCustomError (string errorPage)
+ public void Redirect (string url, bool endResponse)
{
- if (_bHeadersSent)
- return false;
+ Redirect (url, endResponse, 302);
+ }
+#if NET_4_0
+ public void RedirectPermanent (string url)
+ {
+ RedirectPermanent (url, true);
+ }
- if (Request.QueryString ["aspxerrorpath"] != null)
- return false; // Prevent endless loop
+ public void RedirectPermanent (string url, bool endResponse)
+ {
+ Redirect (url, endResponse, 301);
+ }
- Redirect (errorPage + "?aspxerrorpath=" + Request.Path, false);
- return true;
+ public void RedirectToRoute (object routeValues)
+ {
+ RedirectToRoute ("RedirectToRoute", null, new RouteValueDictionary (routeValues), 302, true);
}
-
- public void Write (char ch)
+
+ public void RedirectToRoute (RouteValueDictionary routeValues)
{
- _TextWriter.Write(ch);
+ RedirectToRoute ("RedirectToRoute", null, routeValues, 302, true);
}
- public void Write (object obj)
+ public void RedirectToRoute (string routeName)
{
- _TextWriter.Write(obj);
+ RedirectToRoute ("RedirectToRoute", routeName, null, 302, true);
}
- public void Write (string str)
+ public void RedirectToRoute (string routeName, object routeValues)
{
- _TextWriter.Write (str);
+ RedirectToRoute ("RedirectToRoute", routeName, new RouteValueDictionary (routeValues), 302, true);
}
- public void Write (char [] buffer, int index, int count)
+ 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)
{
- _TextWriter.Write (buffer, index, count);
+ 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)
throw new ArgumentNullException ("path");
-
- if (!UrlUtils.IsRooted (path))
- throw new ArgumentException ("Invalid path for HttpResponse.RemoveOutputCacheItem '" +
- path + "'. An absolute virtual path is expected.");
- Cache cache = HttpRuntime.Cache;
- cache.Remove (path);
+ if (path.Length == 0)
+ return;
+
+ if (path [0] != '/')
+ throw new ArgumentException ("'" + path + "' is not an absolute virtual 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)
{
- if (_bHeadersSent)
- throw new HttpException ("Cannot append cookies after HTTP headers have been sent");
+ AppendCookie (cookie);
+ }
- Cookies.Add (cookie);
+ public void Write (char 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);
}
- private void WriteFromStream (Stream stream, long offset, long length, long bufsize)
+ public void Write (object obj)
{
- if (offset < 0 || length <= 0)
+ 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;
- long stLength = stream.Length;
- if (offset + length > stLength)
- length = stLength - offset;
-
- if (offset > 0)
- stream.Seek (offset, SeekOrigin.Begin);
-
- byte [] fileContent = new byte [bufsize];
- int count = (int) Math.Min (Int32.MaxValue, bufsize);
- while (length > 0 && (count = stream.Read (fileContent, 0, count)) != 0) {
- _Writer.WriteBytes (fileContent, 0, count);
- length -= count;
- count = (int) Math.Min (length, fileContent.Length);
- }
+ writer.Write (obj.ToString ());
+ }
+
+ public void Write (string 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)
+ {
+ 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);
}
+ internal void WriteFile (FileStream fs, long offset, long size)
+ {
+ byte [] buffer = new byte [32*1024];
+
+ if (offset != 0)
+ fs.Position = offset;
+
+ long remain = size;
+ int n;
+ while (remain > 0 && (n = fs.Read (buffer, 0, (int) Math.Min (remain, 32*1024))) != 0){
+ remain -= n;
+ output_stream.Write (buffer, 0, n);
+ }
+ }
+
public void WriteFile (string filename)
{
WriteFile (filename, false);
public void WriteFile (string filename, bool readIntoMemory)
{
- FileStream fs = null;
- try {
- fs = File.OpenRead (filename);
- long size = fs.Length;
- if (readIntoMemory) {
- WriteFromStream (fs, 0, size, size);
- } else {
- WriteFromStream (fs, 0, size, 8192);
- }
- } finally {
- if (fs != null)
- fs.Close ();
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ if (readIntoMemory){
+ using (FileStream fs = File.OpenRead (filename))
+ WriteFile (fs, 0, fs.Length);
+ } else {
+ FileInfo fi = new FileInfo (filename);
+ output_stream.WriteFile (filename, 0, fi.Length);
}
+ if (buffer)
+ return;
+
+ output_stream.ApplyFilter (false);
+ Flush ();
+ }
+
+#if TARGET_JVM
+ public void WriteFile (IntPtr fileHandle, long offset, long size) {
+ throw new PlatformNotSupportedException("IntPtr not supported");
+ }
+#else
+ public void WriteFile (IntPtr fileHandle, long offset, long size)
+ {
+ if (offset < 0)
+ throw new ArgumentNullException ("offset can not be negative");
+ if (size < 0)
+ throw new ArgumentNullException ("size can not be negative");
+
+ if (size == 0)
+ return;
+
+ // Note: this .ctor will throw a SecurityException if the caller
+ // doesn't have the UnmanagedCode permission
+ using (FileStream fs = new FileStream (fileHandle, FileAccess.Read))
+ WriteFile (fs, offset, size);
+
+ if (buffer)
+ return;
+ output_stream.ApplyFilter (false);
+ Flush ();
}
+#endif
public void WriteFile (string filename, long offset, long size)
{
- FileStream fs = null;
- try {
- fs = File.OpenRead (filename);
- WriteFromStream (fs, offset, size, 8192);
- } finally {
- if (fs != null)
- fs.Close ();
- }
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+ if (offset < 0)
+ throw new ArgumentNullException ("offset can not be negative");
+ if (size < 0)
+ throw new ArgumentNullException ("size can not be negative");
+
+ if (size == 0)
+ return;
+
+ FileStream fs = File.OpenRead (filename);
+ WriteFile (fs, offset, size);
+
+ if (buffer)
+ return;
+
+ output_stream.ApplyFilter (false);
+ Flush ();
}
- public void WriteFile (IntPtr fileHandle, long offset, long size)
+ public void WriteSubstitution (HttpResponseSubstitutionCallback callback)
{
- FileStream fs = null;
- try {
- fs = new FileStream (fileHandle, FileAccess.Read);
- WriteFromStream (fs, offset, size, 8192);
- } finally {
- if (fs != null)
- fs.Close ();
+ // 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;
}
- }
- [MonoTODO()]
- internal void OnCookieAdd (HttpCookie cookie)
+ 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);
+ }
+
+ //
+ // Like WriteFile, but never buffers, so we manually Flush here
+ //
+ public void TransmitFile (string filename)
+ {
+ if (filename == null)
+ throw new ArgumentNullException ("filename");
+
+ TransmitFile (filename, false);
+ }
+
+ internal void TransmitFile (string filename, bool final_flush)
+ {
+ FileInfo fi = new FileInfo (filename);
+ using (Stream s = fi.OpenRead ()); // Just check if we can read.
+ output_stream.WriteFile (filename, 0, fi.Length);
+ output_stream.ApplyFilter (final_flush);
+ Flush (final_flush);
+ }
+
+ public void TransmitFile (string filename, long offset, long length)
+ {
+ output_stream.WriteFile (filename, offset, length);
+ output_stream.ApplyFilter (false);
+ Flush (false);
+ }
+
+ internal void TransmitFile (VirtualFile vf)
+ {
+ TransmitFile (vf, false);
+ }
+
+ const int bufLen = 65535;
+ internal void TransmitFile (VirtualFile vf, bool final_flush)
+ {
+ if (vf == null)
+ throw new ArgumentNullException ("vf");
+
+ if (vf is DefaultVirtualFile) {
+ TransmitFile (HostingEnvironment.MapPath (vf.VirtualPath), final_flush);
+ return;
+ }
+
+ byte[] buf = new byte [bufLen];
+ using (Stream s = vf.Open ()) {
+ int readBytes;
+ while ((readBytes = s.Read (buf, 0, bufLen)) > 0) {
+ output_stream.Write (buf, 0, readBytes);
+ output_stream.ApplyFilter (final_flush);
+ Flush (false);
+ }
+ if (final_flush)
+ Flush (true);
+ }
+ }
+
+#region Session state support
+ internal void SetAppPathModifier (string app_modifier)
{
+ app_path_mod = app_modifier;
+ }
+#endregion
+
+#region Cache Support
+ internal void SetCachedHeaders (NameValueCollection headers)
+ {
+ cached_headers = headers;
+
+ }
+
+ internal bool IsCached {
+ get { return cached_response != null; }
+ set {
+ if (value)
+ cached_response = new CachedRawResponse (cache_policy);
+ else
+ cached_response = null;
+ }
}
- [MonoTODO("Do we need this?")]
- internal void OnCookieChange (HttpCookie cookie)
+ public HttpCachePolicy Cache {
+ get {
+ if (cache_policy == null)
+ cache_policy = new HttpCachePolicy ();
+
+ return cache_policy;
+ }
+ }
+
+ internal CachedRawResponse GetCachedResponse ()
{
+ if (cached_response != null) {
+ cached_response.StatusCode = StatusCode;
+ cached_response.StatusDescription = StatusDescription;
+ }
+
+ return cached_response;
}
- [MonoTODO()]
- internal void GoingToChangeCookieColl ()
+ //
+ // This is one of the old ASP compatibility methods, the real cache
+ // control is in the Cache property, and this is a second class citizen
+ //
+ public string CacheControl {
+ set {
+ if (value == null || value == "") {
+ Cache.SetCacheability (HttpCacheability.NoCache);
+ user_cache_control = null;
+ } 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, Helpers.InvariantCulture) == 0) {
+ Cache.SetCacheability (HttpCacheability.Private);
+ user_cache_control = "private";
+ } else if (String.Compare (value, "no-cache", true, Helpers.InvariantCulture) == 0) {
+ Cache.SetCacheability (HttpCacheability.NoCache);
+ user_cache_control = "no-cache";
+ } else
+ throw new ArgumentException ("CacheControl property only allows `public', " +
+ "`private' or no-cache, for different uses, use " +
+ "Response.AppendHeader");
+ }
+
+ get { return (user_cache_control != null) ? user_cache_control : "private"; }
+ }
+#endregion
+
+ internal int GetOutputByteCount ()
{
+ return output_stream.GetTotalLength ();
}
- [MonoTODO()]
- internal void ChangedCookieColl ()
+ internal void ReleaseResources ()
{
+ output_stream.ReleaseResources (true);
+ output_stream = null;
}
}
+
+#if TARGET_J2EE
+ public
+#endif
+ static class FlagEnd
+ {
+ public static readonly object Value = new object ();
+ }
}
+