2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Web / System.Web / HttpResponse.cs
index 2423fdd1b224668f5cd7cee05cea64080c1fea65..734c2018db7a4cf2a6ec79ff1dfa8c58a900aabf 100644 (file)
-// \r
-// System.Web.HttpResponse\r
-//\r
-// Author:\r
-//   Patrik Torstensson (Patrik.Torstensson@labs2.com)\r
-//\r
-using System;\r
-using System.Collections;\r
-using System.IO;\r
-using System.Text;\r
-using System.Globalization;\r
-\r
-namespace System.Web {\r
-   public sealed class HttpResponse {\r
-      // Chunked encoding static helpers\r
-      private static byte [] s_arrChunkSuffix = { 10, 13 };\r
-      private static byte [] s_arrChunkEnd = { 10 , 13 };\r
-      private static string s_sChunkedPrefix = "\r\n";\r
-\r
-      private ArrayList        _Headers;\r
-               \r
-      private bool _bClientDisconnected;\r
-      private bool _bSuppressHeaders;\r
-      private bool _bSuppressContent;\r
-      private bool _bChunked;\r
-      private bool _bEnded;\r
-      private bool _bBuffering;\r
-      private bool _bHeadersSent;\r
-      private bool _bFlushing;\r
-      private long _lContentLength;\r
-      private int _iStatusCode;\r
-\r
-      private bool _ClientDisconnected;\r
-\r
-      private string   _sContentType;\r
-      private string   _sCacheControl;\r
-      private string   _sTransferEncoding;\r
-      private string   _sCharset;\r
-      private string   _sStatusDescription;\r
-\r
-      private HttpCookieCollection _Cookies;\r
-      private HttpCachePolicy _CachePolicy;\r
-\r
-      private Encoding _ContentEncoding;\r
-               \r
-      private HttpContext _Context;\r
-      private HttpWriter _Writer;\r
-      private TextWriter _TextWriter;\r
-\r
-      private HttpWorkerRequest _WorkerRequest;\r
-\r
-      public HttpResponse(TextWriter output) {\r
-         _bBuffering = true;\r
-         _bFlushing = false;\r
-         _bHeadersSent = false;\r
-\r
-         _Headers = new ArrayList();\r
-\r
-         _sContentType = "text/html";\r
-\r
-         _iStatusCode = 200;\r
-         _sCharset = null;\r
-         _sCacheControl = null;\r
-\r
-         _lContentLength = 0;\r
-         _bSuppressContent = false;\r
-         _bSuppressHeaders = false;\r
-         _bClientDisconnected = false;\r
-\r
-         _bChunked = false;\r
-\r
-         _TextWriter = output;\r
-      }\r
-\r
-      internal HttpResponse(HttpWorkerRequest WorkerRequest, HttpContext Context) {\r
-         _Context = Context;\r
-         _WorkerRequest = WorkerRequest;\r
-\r
-         _bBuffering = true;\r
-         _bFlushing = false;\r
-         _bHeadersSent = false;\r
-\r
-         _Headers = new ArrayList();\r
-\r
-         _sContentType = "text/html";\r
-\r
-         _iStatusCode = 200;\r
-         _sCharset = null;\r
-         _sCacheControl = null;\r
-\r
-         _lContentLength = 0;\r
-         _bSuppressContent = false;\r
-         _bSuppressHeaders = false;\r
-         _bClientDisconnected = false;\r
-\r
-         _bChunked = false;\r
-\r
-         _Writer = new HttpWriter(this);\r
-         _TextWriter = _Writer;\r
-      }\r
-\r
-      internal System.Text.Encoder ContentEncoder {\r
-         get {\r
-            return ContentEncoding.GetEncoder();\r
-         }\r
-      }\r
-\r
-      internal void FinalFlush() {\r
-         Flush(true);\r
-      }\r
-\r
-               internal void DoFilter() {\r
-                       if (null != _Writer) \r
-                               _Writer.FilterData(true);\r
-               }\r
-\r
-      [MonoTODO("We need to add cache headers also")]\r
-      private ArrayList GenerateHeaders() {\r
-         ArrayList oHeaders = new ArrayList(_Headers.ToArray());\r
-\r
-         // save culture info, we need us info here\r
-         CultureInfo oSavedInfo = System.Threading.Thread.CurrentThread.CurrentCulture;\r
-         System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(0x0409);\r
-\r
-         oHeaders.Add(new HttpResponseHeader("Date", DateTime.Now.ToUniversalTime().ToString("ddd, d MMM yyyy HH:mm:ss") + " GMT"));\r
-\r
-         System.Threading.Thread.CurrentThread.CurrentCulture = oSavedInfo;\r
-\r
-         if (_lContentLength > 0) {\r
-            oHeaders.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderContentLength, _lContentLength.ToString()));\r
-         }\r
-\r
-         if (_sContentType != null) {\r
-            if (_sContentType.IndexOf("charset=") == -1) {\r
-               if (Charset.Length == 0) {\r
-                  Charset = ContentEncoding.HeaderName;\r
-               }\r
-\r
-               // Time to build our string\r
-               if (Charset.Length > 0) {\r
-                  _sContentType += "; charset=" + Charset;\r
-               }\r
-            }\r
-\r
-            oHeaders.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderContentType, _sContentType));\r
-         }\r
-\r
-         if (_sCacheControl != null) {\r
-            oHeaders.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderPragma, _sCacheControl));\r
-         }\r
-\r
-         if (_sTransferEncoding != null) {\r
-            oHeaders.Add(new HttpResponseHeader(HttpWorkerRequest.HeaderTransferEncoding, _sTransferEncoding));\r
-         }\r
-\r
-         // TODO: Add Cookie headers..\r
-\r
-         return oHeaders;\r
-      }\r
-\r
-      private void SendHeaders() {\r
-         _WorkerRequest.SendStatus(StatusCode, StatusDescription);\r
-                       \r
-         ArrayList oHeaders = GenerateHeaders();\r
-         foreach (object oHeader in oHeaders) {\r
-            ((HttpResponseHeader) oHeader).SendContent(_WorkerRequest);\r
-         }\r
-                       \r
-         _bHeadersSent = true;\r
-      }\r
-\r
-      public string Status {\r
-         get {\r
-            return StatusCode.ToString() + " " + StatusDescription;\r
-         }\r
-\r
-         set {\r
-            string sMsg = "OK";\r
-            int iCode = 200;\r
-\r
-            try {\r
-               iCode = Int32.Parse(value.Substring(0, value.IndexOf(' ')));\r
-               sMsg = value.Substring(value.IndexOf(' ') + 1);\r
-            }\r
-            catch(Exception) {\r
-               throw new HttpException("Invalid status string");\r
-            }\r
-\r
-            StatusCode = iCode;\r
-            StatusDescription = sMsg;\r
-         }\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AddCacheItemDependencies(ArrayList cacheKeys) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AddCacheItemDependency(string cacheKey) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AddFileDependencies(ArrayList filenames) {\r
-         //throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AddFileDependency(string filename) {\r
-         //throw new NotImplementedException();\r
-      }\r
-\r
-      public void AddHeader(string name, string value) {\r
-         AppendHeader(name, value);\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AppendCookie(HttpCookie cookie) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void AppendToLog(string param) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public string ApplyAppPathModifier(string virtualPath) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      public bool Buffer {\r
-         get {\r
-            return BufferOutput;\r
-         }\r
-                       \r
-         set {\r
-            BufferOutput = value;\r
-         }\r
-      }\r
-\r
-      public bool BufferOutput {\r
-         get {\r
-            return _bBuffering;\r
-         }\r
-                       \r
-         set {\r
-            if (_Writer != null) {\r
-               _Writer.Update();\r
-            }\r
-\r
-            _bBuffering = value;\r
-         }\r
-      }\r
-\r
-      public HttpCachePolicy Cache {\r
-         get {\r
-            if (null == _CachePolicy) {\r
-               _CachePolicy = new HttpCachePolicy();\r
-            }\r
-\r
-            return _CachePolicy;\r
-         }\r
-      }\r
-\r
-      [MonoTODO("Set status in the cache policy")]\r
-      public string CacheControl {\r
-         get {\r
-            return _sCacheControl;\r
-         }\r
-\r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _sCacheControl = value;\r
-         }\r
-      }\r
-\r
-      public string Charset {\r
-         get { \r
-            if (null == _sCharset) {\r
-               _sCharset = ContentEncoding.WebName;\r
-            }\r
-\r
-            return _sCharset;\r
-         }\r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _sCharset = value;\r
-         }\r
-      }\r
-\r
-      public Encoding ContentEncoding {\r
-         get {\r
-            if (_ContentEncoding == null) {\r
-               _ContentEncoding = Encoding.UTF8;\r
-            }\r
-\r
-            return _ContentEncoding;\r
-         }\r
-\r
-         set {\r
-            if (value == null) {\r
-               throw new ArgumentException("Can't set a null as encoding");\r
-            }\r
-\r
-            _ContentEncoding = value;\r
-\r
-            if (_Writer != null) {\r
-               _Writer.Update();\r
-            }\r
-         }\r
-      }\r
-\r
-      public string ContentType {\r
-         get {\r
-            return _sContentType;\r
-         }\r
-\r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _sContentType = value;\r
-         }\r
-      }\r
-\r
-      public HttpCookieCollection Cookies {\r
-         get {\r
-            if (null == _Cookies) {\r
-               _Cookies = new HttpCookieCollection(this, false);\r
-            }\r
-            return _Cookies;\r
-         }\r
-      }\r
-\r
-      [MonoTODO("Set expires in the cache policy")]\r
-      public int Expires {\r
-         get {\r
-            throw new NotImplementedException();\r
-         }\r
-\r
-         set {\r
-            throw new NotImplementedException();\r
-         }\r
-      }\r
-\r
-      [MonoTODO("Set expiresabsolute in the cache policy")]\r
-      public DateTime ExpiresAbsolute {\r
-         get {\r
-            throw new NotImplementedException();\r
-         }\r
-\r
-         set {\r
-            throw new NotImplementedException();\r
-         }\r
-      }\r
-\r
-      public Stream Filter {\r
-         get {\r
-            if (_Writer != null) {\r
-               return _Writer.GetActiveFilter();\r
-            }\r
-            return null;\r
-         }\r
-\r
-         set {\r
-            if (_Writer == null) {\r
-               throw new HttpException("Filtering is not allowed");\r
-            }\r
-\r
-            _Writer.ActivateFilter(value);\r
-         }\r
-      }\r
-\r
-      public bool IsClientConnected {\r
-         get {\r
-            if (_ClientDisconnected) {\r
-               return false;\r
-            }\r
-\r
-            if (null != _WorkerRequest && (!_WorkerRequest.IsClientConnected())) {\r
-               _ClientDisconnected = false;\r
-               return false;\r
-            }\r
-\r
-            return true;\r
-         }\r
-      }\r
-      \r
-      public TextWriter Output {\r
-         get {\r
-            return _TextWriter;\r
-         }\r
-      }\r
-\r
-      public Stream OutputStream {\r
-         get {\r
-            if (_Writer == null) {\r
-               throw new System.Web.HttpException("a Output stream not available when running with custom text writer");\r
-            }\r
-\r
-            return _Writer.OutputStream;\r
-         }\r
-      }\r
-\r
-      public string StatusDescription {\r
-         get {\r
-            if (null == _sStatusDescription) {\r
-               _sStatusDescription = HttpWorkerRequest.GetStatusDescription(_iStatusCode);\r
-            } \r
-               \r
-            return _sStatusDescription;\r
-         }\r
-\r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _sStatusDescription = value;\r
-         }\r
-      }\r
-       \r
-      public int StatusCode {\r
-         get {\r
-            return _iStatusCode;\r
-         }\r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _sStatusDescription = null;\r
-            _iStatusCode = value;\r
-         }\r
-      }\r
-\r
-      public bool SuppressContent {\r
-         get {\r
-            return _bSuppressContent;\r
-         }\r
-                       \r
-         set {\r
-            if (_bHeadersSent) {\r
-               throw new System.Web.HttpException("Headers has been sent to the client");\r
-            }\r
-\r
-            _bSuppressContent = true;\r
-         }\r
-      }\r
-\r
-      public HttpRequest Request {\r
-         get {\r
-            return _Context.Request;\r
-         }\r
-      }\r
-\r
-      internal void AppendHeader(int iIndex, string value) {\r
-         if (_bHeadersSent) {\r
-            throw new System.Web.HttpException("Headers has been sent to the client");\r
-         }\r
-         switch (iIndex) {\r
-            case HttpWorkerRequest.HeaderContentLength :       \r
-               _lContentLength = Int64.Parse(value);\r
-               break;\r
-            case HttpWorkerRequest.HeaderContentEncoding :     \r
-               _sContentType = value;\r
-               break;\r
-            case HttpWorkerRequest.HeaderTransferEncoding :    \r
-               _sTransferEncoding = value;\r
-               if (value.Equals("chunked")) {\r
-                  _bChunked = true;\r
-               } else {\r
-                  _bChunked = false;\r
-               }\r
-               break;\r
-\r
-            case HttpWorkerRequest.HeaderPragma        :       \r
-               _sCacheControl = value;\r
-               break;\r
-\r
-            default    :       \r
-               _Headers.Add(new HttpResponseHeader(iIndex, value));\r
-               break;\r
-         }\r
-      \r
-\r
-      }\r
-\r
-      public void AppendHeader(string name, string value) {\r
-         if (_bHeadersSent) {\r
-            throw new System.Web.HttpException("Headers has been sent to the client");\r
-         }\r
-       \r
-         switch (name.ToLower()) {\r
-            case "content-length"              :       _lContentLength = Int64.Parse(value);\r
-               break;\r
-            case "content-type"                        :       _sContentType = value;\r
-               break;\r
-            case "transfer-encoding"   :       _sTransferEncoding = value;\r
-               if (value.Equals("chunked")) {\r
-                  _bChunked = true;\r
-               } else {\r
-                  _bChunked = false;\r
-               }\r
-\r
-               break;\r
-            case "pragma"                              :       _sCacheControl = value;\r
-               break;\r
-\r
-            default                                            :       _Headers.Add(new HttpResponseHeader(name, value));\r
-               break;\r
-         }\r
-      }\r
-       \r
-      public void BinaryWrite(byte [] buffer) {\r
-         OutputStream.Write(buffer, 0, buffer.Length);\r
-      }\r
-\r
-      public void Clear() {\r
-         if (_Writer != null) {\r
-            _Writer.Clear();\r
-         }\r
-      }\r
-\r
-      public void ClearContent() {\r
-         Clear();\r
-      }\r
-\r
-      public void ClearHeaders() {\r
-         if (_bHeadersSent) {\r
-            throw new System.Web.HttpException("Headers has been sent to the client");\r
-         }\r
-\r
-         _sContentType = "text/html";\r
-\r
-         _iStatusCode = 200;\r
-         _sCharset = null;\r
-         _Headers = new ArrayList();\r
-         _sCacheControl = null;\r
-         _sTransferEncoding = null;\r
-\r
-         _lContentLength = 0;\r
-         _bSuppressContent = false;\r
-         _bSuppressHeaders = false;\r
-         _bClientDisconnected = false;\r
-      }\r
-\r
-      public void Close() {\r
-         _bClientDisconnected = false;\r
-\r
-         _WorkerRequest.CloseConnection();\r
-\r
-         _bClientDisconnected = true;\r
-      }\r
-\r
-      internal void Dispose() {\r
-         if (_Writer != null) {\r
-            _Writer.Dispose();\r
-            _Writer = null;\r
-         }\r
-      }\r
-\r
-      [MonoTODO("Handle callbacks into before done with session, needs to have a non ended flush here")]\r
-      internal void FlushAtEndOfRequest() \r
-      {\r
-         Flush(true);\r
-      }\r
-\r
-      [MonoTODO("Check timeout and if we can cancel the thread...")]\r
-      public void End() {\r
-         if (!_bEnded) {\r
-            Flush();\r
-            _WorkerRequest.CloseConnection();\r
-\r
-            _bEnded = true;\r
-         }\r
-      }\r
-\r
-      public void Flush() {\r
-         Flush(false);\r
-      }\r
-\r
-      private void Flush(bool bFinish) {\r
-         if (_bFlushing) {\r
-            return;\r
-         }\r
-\r
-         _bFlushing = true;\r
-\r
-         if (_Writer != null) {\r
-            _Writer.FlushBuffers();\r
-         } else {\r
-            _TextWriter.Flush();\r
-         }\r
-\r
-         try {\r
-            if (!_bHeadersSent) {\r
-               if (!_bSuppressHeaders && !_bClientDisconnected) {\r
-                  if (_Writer != null && BufferOutput) {\r
-                     _lContentLength = _Writer.BufferSize;\r
-                  } \r
-                  else {\r
-                     _lContentLength = 0;\r
-                  }\r
-               \r
-                  if (_lContentLength == 0 && _iStatusCode == 200 && _sTransferEncoding == null) {\r
-                     // Check we are going todo chunked encoding\r
-                     string sProto = _Context.Request.ServerVariables["SERVER_PROTOCOL"];\r
-                     if (sProto != null && sProto == "HTTP/1.1") {\r
-                        AppendHeader(HttpWorkerRequest.HeaderTransferEncoding, "chunked");\r
-                     }  \r
-                     else {\r
-                        // Just in case, the old browsers sends a HTTP/1.0 request with Connection: Keep-Alive\r
-                        AppendHeader(HttpWorkerRequest.HeaderConnection, "Close");\r
-                     }\r
-                  } \r
-\r
-                  SendHeaders();\r
-               }                                       \r
-            }  \r
-            if ((!_bSuppressContent && Request.HttpMethod.Equals("HEAD")) || _Writer == null) {\r
-               _bSuppressContent = true;\r
-            }\r
-\r
-            if (!_bSuppressContent) {\r
-               _bClientDisconnected = false;\r
-               if (_bChunked) {\r
-                  Encoding oASCII = Encoding.ASCII;\r
-\r
-                  byte [] arrPrefix = oASCII.GetBytes(Convert.ToString(_Writer.BufferSize, 16) + s_sChunkedPrefix);\r
-                  _WorkerRequest.SendResponseFromMemory(arrPrefix, arrPrefix.Length);\r
-\r
-                  _Writer.SendContent(_WorkerRequest);\r
-\r
-                  _WorkerRequest.SendResponseFromMemory(s_arrChunkSuffix, s_arrChunkSuffix.Length);\r
-                  if (bFinish) {\r
-                     _WorkerRequest.SendResponseFromMemory(s_arrChunkEnd, s_arrChunkEnd.Length);\r
-                  }\r
-               } \r
-               else {\r
-                  _Writer.SendContent(_WorkerRequest);\r
-               }\r
-\r
-               _WorkerRequest.FlushResponse(bFinish);  \r
-\r
-               if (!bFinish) {\r
-                  _Writer.Clear();\r
-               }\r
-            }\r
-         }\r
-         finally {\r
-            _bFlushing = false;\r
-         }\r
-      }\r
-\r
-      public void Pics(string value) {\r
-         AppendHeader("PICS-Label", value);\r
-      }\r
-\r
-\r
-      public void Redirect(string url) {\r
-         Redirect(url, true);\r
-      }\r
-\r
-      //FIXME: [1] this is an ugly hack to make it work until we have SimpleWorkerRequest!\r
-      private string redirectLocation;\r
-      public string RedirectLocation\r
-      {\r
-             get {\r
-                     return redirectLocation;\r
-             }\r
-      }\r
-      public void Redirect(string url, bool endResponse) {\r
-         if (_bHeadersSent) {\r
-            throw new System.Web.HttpException("Headers has been sent to the client");\r
-         }\r
-\r
-         Clear();\r
-\r
-         StatusCode = 302;\r
-        redirectLocation = url;\r
-         //[1]AppendHeader(HttpWorkerRequest.HeaderLocation, url);\r
-\r
-         // Text for browsers that can't handle location header\r
-         Write("<html><head><title>Object moved</title></head><body>\r\n");\r
-         Write("<h2>Object moved to <a href='" + url + "'>here</a></h2>\r\n");\r
-         Write("</body><html>\r\n");\r
-\r
-         /* [1]\r
-        if (endResponse) {\r
-            End();\r
-         }\r
-        */\r
-      }\r
-\r
-      public void Write(char ch) {\r
-         _TextWriter.Write(ch);\r
-      }\r
-\r
-      public void Write(object obj) {\r
-         _TextWriter.Write(obj);\r
-      }\r
-\r
-      public void Write(string str) {\r
-         _TextWriter.Write(str);\r
-      }\r
-\r
-      public void Write(char [] buffer, int index, int count) {\r
-         _TextWriter.Write(buffer, index, count);\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public static void RemoveOutputCacheItem(string path) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void SetCookie(HttpCookie cookie) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      public void WriteFile(string filename) {\r
-         WriteFile(filename, false);\r
-      }\r
-\r
-      [MonoTODO()]\r
-      public void WriteFile(string filename, bool readIntoMemory) {\r
-         throw new NotImplementedException();\r
-      }\r
-      \r
-      [MonoTODO()]\r
-      public void WriteFile(string filename, long offset, long size) {\r
-         throw new NotImplementedException();\r
-      }\r
-\r
-      [MonoTODO("Should we support fileHandle ptrs?")]\r
-      public void WriteFile(IntPtr fileHandle, long offset, long size) {\r
-      }   \r
-\r
-      [MonoTODO()]\r
-      internal void OnCookieAdd(HttpCookie cookie) {\r
-      }\r
-\r
-      [MonoTODO("Do we need this?")]\r
-      internal void OnCookieChange(HttpCookie cookie) {\r
-      }\r
-\r
-      [MonoTODO()]\r
-      internal void GoingToChangeCookieColl() {\r
-      }\r
-\r
-      [MonoTODO()]\r
-      internal void ChangedCookieColl() {\r
-      }\r
-   }\r
-}\r
+// 
+// System.Web.HttpResponse
+//
+// Authors:
+//     Patrik Torstensson (Patrik.Torstensson@labs2.com)
+//     Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// (c) 2002 Ximian, Inc. (http://www.ximian.com)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// 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.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Web.Util;
+using System.Web.Caching;
+
+namespace System.Web
+{
+       public sealed 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";
+
+               ArrayList _Headers;
+                       
+               bool _bClientDisconnected;
+               bool _bSuppressHeaders;
+               bool _bSuppressContent;
+               bool _bChunked;
+               bool _bEnded;
+               bool _bBuffering;
+               bool _bHeadersSent;
+               bool _bFlushing;
+               bool filtered;
+               long _lContentLength;
+               int _iStatusCode;
+               
+               int _expiresInMinutes;
+               bool _expiresInMinutesSet;
+               DateTime _expiresAbsolute;
+               bool _expiresAbsoluteSet;
+
+               bool _ClientDisconnected;
+               bool closed;
+
+               string  _sContentType;
+               string  _sCacheControl;
+               string  _sTransferEncoding;
+               string  _sCharset;
+               string  _sStatusDescription;
+
+               HttpCookieCollection _Cookies;
+               HttpCachePolicy _CachePolicy;
+
+               Encoding _ContentEncoding;
+                       
+               HttpContext _Context;
+               HttpWriter _Writer;
+               TextWriter _TextWriter;
+
+               HttpWorkerRequest _WorkerRequest;
+
+               ArrayList fileDependencies;
+               CachedRawResponse cached_response;
+               ArrayList cached_headers;
+#if NET_1_1
+               string redirectLocation;
+#endif
+
+               string app_path_mod = null;
+                
+               public HttpResponse (TextWriter output)
+               {
+                        _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;
+               }
+
+               internal HttpResponse (HttpWorkerRequest WorkerRequest, HttpContext Context)
+               {
+                        _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);
+               }
+
+               internal void DoFilter (bool really)
+               {
+                       if (really && null != _Writer) 
+                               _Writer.FilterData (true);
+
+                       filtered = true;
+               }
+
+               internal bool IsCached {
+                       get { return cached_response != null; }
+               }
+
+               internal CachedRawResponse GetCachedResponse () {
+                       cached_response.StatusCode = StatusCode;
+                       cached_response.StatusDescription = StatusDescription;
+                       return cached_response;
+               }
+
+               internal void SetCachedHeaders (ArrayList headers)
+               {
+                       cached_headers = headers;
+               }
+               
+               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 ()));
+                       }
+
+                       if (_sContentType != null) {
+                               if (_sContentType.IndexOf ("charset=") == -1) {
+                                       if (Charset.Length == 0) {
+                                               Charset = ContentEncoding.HeaderName;
+                                       }
+
+                                       // Time to build our string
+                                       if (Charset.Length > 0) {
+                                               _sContentType += "; charset=" + Charset;
+                                       }
+                               }
+
+                               oHeaders.Add (new HttpResponseHeader (HttpWorkerRequest.HeaderContentType,
+                                                                     _sContentType));
+                       }
+
+                       if (_CachePolicy != null)
+                               _CachePolicy.SetHeaders (this, oHeaders);
+                       
+                       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 ());
+                               }
+                       }
+#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;
+               }
+
+               public string Status
+               {
+                       get {
+                               return String.Format ("{0} {1}", StatusCode, StatusDescription);
+                       }
+
+                       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;
+                       }
+               }
+
+               [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;
+                       }
+
+                       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 ();
+               }
+
+               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);
+                       }
+
+                       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;
+
+                               virtualPath = UrlUtils.Combine (rvd, virtualPath.Substring (basevd.Length));
+                       }
+
+                       return virtualPath;
+               }
+
+               internal void SetAppPathModifier (string app_path_mod)
+               {
+                       this.app_path_mod = app_path_mod;
+               }
+               
+               public bool Buffer
+               {
+                       get {
+                               return BufferOutput;
+                       }
+
+                       set {
+                               BufferOutput = value;
+                       }
+               }
+
+               public bool BufferOutput
+               {
+                       get {
+                               return _bBuffering;
+                       }
+                       
+                       set {
+                               if (_Writer != null)
+                                       _Writer.Update ();
+
+                               _bBuffering = value;
+                       }
+               }
+
+               public HttpCachePolicy Cache
+               {
+                       get {
+                               if (null == _CachePolicy) {
+                                       _CachePolicy = new HttpCachePolicy ();
+                                       _CachePolicy.CacheabilityUpdated += new CacheabilityUpdatedCallback (
+                                               OnCacheabilityUpdated);
+                               }
+
+                               return _CachePolicy;
+                       }
+               }
+
+               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
+               {
+                       get {
+                               return _sCacheControl;
+                       }
+
+                       set {
+                               if (_bHeadersSent)
+                                       throw new HttpException ("Headers has been sent to the client");
+
+                               _sCacheControl = value;
+                       }
+               }
+
+               public string Charset
+               {
+                       get {
+                               if (null == _sCharset)
+                                       _sCharset = ContentEncoding.WebName;
+
+                               return _sCharset;
+                       }
+
+                       set {
+                               if (_bHeadersSent)
+                                       throw new HttpException ("Headers has been sent to the client");
+
+                               _sCharset = value;
+                       }
+               }
+
+               public Encoding ContentEncoding
+               {
+                       get {
+                               if (_ContentEncoding == null)
+                                       _ContentEncoding = WebEncoding.ResponseEncoding;
+
+                               return _ContentEncoding;
+                       }
+
+                       set {
+                               if (value == null)
+                                       throw new ArgumentNullException ("Can't set a null as encoding");
+
+                               _ContentEncoding = value;
+
+                               if (_Writer != null)
+                                       _Writer.Update ();
+                       }
+               }
+
+               public string ContentType
+               {
+                       get {
+                               return _sContentType;
+                       }
+
+                       set {
+                               if (_bHeadersSent)
+                                       throw new HttpException ("Headers has been sent to the client");
+
+                               _sContentType = value;
+                       }
+               }
+
+               public HttpCookieCollection Cookies
+               {
+                       get {
+                               if (null == _Cookies)
+                                       _Cookies = new HttpCookieCollection (this, false);
+
+                               return _Cookies;
+                       }
+               }
+
+               public int Expires
+               {
+                       get {
+                               return _expiresInMinutes;
+                       }
+
+                       set {
+                               if (!_expiresInMinutesSet || (value < _expiresInMinutes))
+                               {
+                                       _expiresInMinutes = value;
+                                       Cache.SetExpires(_Context.Timestamp.Add(new TimeSpan(0, _expiresInMinutes, 0)));
+                               }
+                               _expiresInMinutesSet = true;
+                       }
+               }
+
+               public DateTime ExpiresAbsolute
+               {
+                       get {
+                               return _expiresAbsolute;
+                       }
+
+                       set {
+                               if (!_expiresAbsoluteSet || value.CompareTo(_expiresAbsolute)<0)
+                               {
+                                       _expiresAbsolute = value;
+                                       Cache.SetExpires(_expiresAbsolute); 
+                               }
+                               _expiresAbsoluteSet = true;
+                       }
+               }
+
+               public Stream Filter
+               {
+                       get {
+                               if (_Writer != null)
+                                       return _Writer.GetActiveFilter ();
+
+                               return null;
+                       }
+
+                       set {
+                               if (_Writer == null)
+                                       throw new HttpException ("Filtering is not allowed");
+
+                               _Writer.ActivateFilter (value);
+                       }
+               }
+
+               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;
+                       }
+               }
+
+               public Stream OutputStream
+               {
+                       get {
+                               if (_Writer == null)
+                                       throw new HttpException ("an Output stream not available when " +
+                                                                "running with custom text writer");
+
+                               return _Writer.OutputStream;
+                       }
+               }
+
+#if NET_1_1
+               public string RedirectLocation {
+                       get { return redirectLocation; }
+                       set { redirectLocation = value; }
+               }
+#endif
+               
+               public string StatusDescription
+               {
+                       get {
+                               if (null == _sStatusDescription)
+                                       _sStatusDescription =
+                                               HttpWorkerRequest.GetStatusDescription (_iStatusCode);
+
+                               return _sStatusDescription;
+                       }
+
+                       set {
+                               if (_bHeadersSent)
+                                       throw new HttpException ("Headers has been sent to the client");
+
+                               _sStatusDescription = value;
+                       }
+               }
+       
+               public int StatusCode
+               {
+                       get {
+                               return _iStatusCode;
+                       }
+
+                       set {
+                               if (_bHeadersSent)
+                                       throw new HttpException ("Headers has been sent to the client");
+
+                               _sStatusDescription = null;
+                               _iStatusCode = value;
+                       }
+               }
+
+               public bool SuppressContent
+               {
+                       get {
+                               return _bSuppressContent;
+                       }
+                       
+                       set {
+                               _bSuppressContent = true;
+                       }
+               }
+
+               HttpRequest Request
+               {
+                       get {
+                               if (_Context == null)
+                                       return null;
+
+                               return _Context.Request;
+                       }
+               }
+
+               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;
+                       }
+               }
+
+               public void AppendHeader (string name, string value)
+               {
+                       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;
+                       }
+               }
+       
+               internal TextWriter SetTextWriter (TextWriter w)
+               {
+                       TextWriter prev = _TextWriter;
+                       _TextWriter = w;
+                       return prev;
+               }
+               
+               public void BinaryWrite (byte [] buffer)
+               {
+                       OutputStream.Write (buffer, 0, buffer.Length);
+               }
+
+               internal void BinaryWrite (byte [] buffer, int start, int length)
+               {
+                       OutputStream.Write (buffer, start, length);
+               }
+               
+               public void Clear ()
+               {
+                       if (_Writer != null)
+                               _Writer.Clear ();
+               }
+
+               public void ClearContent ()
+               {
+                       Clear();
+               }
+
+               internal void SetHeadersSent (bool val)
+               {
+                       _bHeadersSent = val;
+               }
+               
+               public void ClearHeaders ()
+               {
+                       if (_bHeadersSent)
+                               throw new HttpException ("Headers has been sent to the client");
+
+                       _sContentType = "text/html";
+
+                       _iStatusCode = 200;
+                       _sCharset = null;
+                       _Headers = new ArrayList ();
+                       _sCacheControl = null;
+                       _sTransferEncoding = null;
+
+                       _lContentLength = 0;
+                       _bSuppressContent = false;
+                       _bSuppressHeaders = false;
+                       _bClientDisconnected = false;
+               }
+
+               public void Close ()
+               {
+                       if (closed && !_bClientDisconnected) {
+                               _bClientDisconnected = false;
+                               _WorkerRequest.CloseConnection ();
+                               _bClientDisconnected = true;
+                       }
+               }
+
+               internal void Dispose ()
+               {
+                       if (_Writer != null) {
+                               _Writer.Dispose ();
+                               _Writer = null;
+                       }
+               }
+
+               [MonoTODO("Handle callbacks into before done with session, needs to have a non ended flush here")]
+               internal void FlushAtEndOfRequest () 
+               {
+                       Flush (true);
+               }
+
+               public void End ()
+               {
+                       if (_bEnded)
+                               return;
+
+                       if (_Context.TimeoutPossible)
+                               Thread.CurrentThread.Abort (new StepCompleteRequest ());
+
+                       Flush ();
+                       _bEnded = true;
+                       _Context.ApplicationInstance.CompleteRequest ();
+               }
+
+               public void Flush ()
+               {
+                       if (closed)
+                               throw new HttpException ("Response already finished.");
+
+                       Flush (false);
+               }
+
+               private void Flush (bool bFinish)
+               {
+                       if (_bFlushing || closed)
+                               return;
+
+                       _bFlushing = true;
+
+                       if (_Writer == null) {
+                               _TextWriter.Flush ();
+                               _bFlushing = false;
+                               return;
+                       }
+
+                       try {
+                               if (_bClientDisconnected)
+                                       return;
+
+                               long length = _Writer.BufferSize;
+                               if (!_bHeadersSent && !_bSuppressHeaders) {
+                                       if (bFinish) {
+                                               if (length == 0 && _lContentLength == 0)
+                                                       _sContentType = null;
+
+                                               SendHeaders ();
+                                               length = _Writer.BufferSize;
+                                               if (length != 0)
+                                                       _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 ();
+                                       }
+                               }
+
+                               if (!filtered) {
+                                       _Writer.FilterData (false);
+                                       length = _Writer.BufferSize;
+                               }
+
+                               if (length == 0) {
+                                       if (bFinish && _bChunked) {
+                                               _WorkerRequest.SendResponseFromMemory (s_arrChunkEnd,
+                                                                               s_arrChunkEnd.Length);
+                                       }
+
+                                       _WorkerRequest.FlushResponse (bFinish);
+                                       if (!bFinish)
+                                               _Writer.Clear ();
+                                       return;
+                               }
+
+                               if (!_bSuppressContent && Request.HttpMethod == "HEAD")
+                                       _bSuppressContent = true;
+
+                               if (_bSuppressContent)
+                                       _Writer.Clear ();
+
+                               if (!_bSuppressContent) {
+                                       _bClientDisconnected = false;
+                                       if (_bChunked) {
+                                               Encoding oASCII = Encoding.ASCII;
+
+                                               string chunk = Convert.ToString(_Writer.BufferSize, 16);
+                                               byte [] arrPrefix = oASCII.GetBytes (chunk + s_sChunkedPrefix);
+
+                                               _WorkerRequest.SendResponseFromMemory (arrPrefix,
+                                                                                      arrPrefix.Length);
+
+                                               _Writer.SendContent (_WorkerRequest);
+
+                                               _WorkerRequest.SendResponseFromMemory (s_arrChunkSuffix,
+                                                                                      s_arrChunkSuffix.Length);
+                                               if (bFinish)
+                                                       _WorkerRequest.SendResponseFromMemory (
+                                                                       s_arrChunkEnd, s_arrChunkEnd.Length);
+                                       } else {
+                                               _Writer.SendContent (_WorkerRequest);
+                                       }
+                               }
+
+                               _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)
+               {
+                       AppendHeader ("PICS-Label", value);
+               }
+
+
+               public void Redirect (string url)
+               {
+                       Redirect (url, true);
+               }
+
+               public void Redirect (string url, bool endResponse)
+               {
+                       if (_bHeadersSent)
+                               throw new HttpException ("Headers has been sent to the client");
+
+                       Clear ();
+
+                       url = ApplyAppPathModifier (url);
+                       StatusCode = 302;
+                       AppendHeader (HttpWorkerRequest.HeaderLocation, 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 ("</body><html>\r\n");
+
+                       if (endResponse)
+                               End ();
+               }
+
+               internal bool RedirectCustomError (string errorPage)
+               {
+                       if (_bHeadersSent)
+                               return false;
+
+                       if (Request.QueryString ["aspxerrorpath"] != null)
+                               return false; // Prevent endless loop
+
+                       Redirect (errorPage + "?aspxerrorpath=" + Request.Path, false);
+                       return true;
+               }
+               
+               public void Write (char ch)
+               {
+                       _TextWriter.Write(ch);
+               }
+
+               public void Write (object obj)
+               {
+                       _TextWriter.Write(obj);
+               }
+
+               public void Write (string str)
+               {
+                       _TextWriter.Write (str);
+               }
+
+               public void Write (char [] buffer, int index, int count)
+               {
+                       _TextWriter.Write (buffer, index, count);
+               }
+
+               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);
+               }
+
+               public void SetCookie (HttpCookie cookie)
+               {
+                       if (_bHeadersSent)
+                               throw new HttpException ("Cannot append cookies after HTTP headers have been sent");
+
+                       Cookies.Add (cookie);
+               }
+
+               private void WriteFromStream (Stream stream, long offset, long length, long bufsize)
+               {
+                       if (offset < 0 || length <= 0)
+                               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);
+                       }
+               }
+
+               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 ();
+                       }
+               }
+
+               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 ();
+                       }
+               }
+
+               public void WriteFile (IntPtr fileHandle, long offset, long size)
+               {
+                       FileStream fs = null;
+                       try {
+                               fs = new FileStream (fileHandle, FileAccess.Read);
+                               WriteFromStream (fs, offset, size, 8192);
+                       } finally {
+                               if (fs != null)
+                                       fs.Close ();
+                       }
+               }   
+
+               [MonoTODO()]
+               internal void OnCookieAdd (HttpCookie cookie)
+               {
+               }
+
+               [MonoTODO("Do we need this?")]
+               internal void OnCookieChange (HttpCookie cookie)
+               {
+               }
+
+               [MonoTODO()]
+               internal void GoingToChangeCookieColl ()
+               {
+               }
+
+               [MonoTODO()]
+               internal void ChangedCookieColl ()
+               {
+               }
+       }
+}