-// \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
- [MonoTODO("Verify that this really works")]\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
- [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
- 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
- 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
- if (endResponse) {\r
- End();\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)
+//
+using System;
+using System.Collections;
+using System.Globalization;
+using System.IO;
+using System.Text;
+using System.Threading;
+using System.Web.Util;
+
+namespace System.Web
+{
+ public sealed class HttpResponse
+ {
+ // Chunked encoding static helpers
+ static byte [] s_arrChunkSuffix = { 10, 13 };
+ static byte [] s_arrChunkEnd = { 10 , 13 };
+ 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;
+
+ bool _ClientDisconnected;
+
+ 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;
+
+ 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;
+
+ _Writer = new HttpWriter (this);
+ _TextWriter = _Writer;
+ }
+
+ internal Encoder ContentEncoder
+ {
+ get {
+ return ContentEncoding.GetEncoder ();
+ }
+ }
+
+ internal void FinalFlush ()
+ {
+ Flush (true);
+ }
+
+ internal void DoFilter (bool really)
+ {
+ if (really && null != _Writer)
+ _Writer.FilterData (true);
+
+ filtered = true;
+ }
+
+ [MonoTODO("We need to add cache headers also")]
+ 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 = new CultureInfo (0x0409);
+
+ string date = DateTime.Now.ToUniversalTime ().ToString ("ddd, d MMM yyyy HH:mm:ss ");
+ oHeaders.Add (new HttpResponseHeader ("Date", date + "GMT"));
+
+ 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 (_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 ());
+ }
+ }
+
+ return oHeaders;
+ }
+
+ private void SendHeaders ()
+ {
+ _WorkerRequest.SendStatus (StatusCode, StatusDescription);
+
+ ArrayList oHeaders = GenerateHeaders ();
+ 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);
+ }
+
+ return virtualPath;
+ }
+
+ 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 ();
+
+ return _CachePolicy;
+ }
+ }
+
+ [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.Encoding;
+
+ return _ContentEncoding;
+ }
+
+ set {
+ if (value == null)
+ throw new ArgumentException ("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;
+ }
+ }
+
+ [MonoTODO("Set expires in the cache policy")]
+ public int Expires
+ {
+ get {
+ throw new NotImplementedException ();
+ }
+
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ [MonoTODO("Set expiresabsolute in the cache policy")]
+ public DateTime ExpiresAbsolute
+ {
+ get {
+ throw new NotImplementedException ();
+ }
+
+ set {
+ throw new NotImplementedException ();
+ }
+ }
+
+ 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;
+ }
+ }
+
+ 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 {
+ if (_bHeadersSent)
+ throw new HttpException ("Headers has been sent to the client");
+
+ _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;
+ if (value.Equals ("chunked")) {
+ _bChunked = true;
+ } else {
+ _bChunked = false;
+ }
+ 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;
+ if (value.Equals ("chunked")) {
+ _bChunked = true;
+ } else {
+ _bChunked = false;
+ }
+ break;
+ case "pragma":
+ _sCacheControl = value;
+ break;
+ default:
+ _Headers.Add (new HttpResponseHeader (name, value));
+ break;
+ }
+ }
+
+ public void BinaryWrite (byte [] buffer)
+ {
+ OutputStream.Write (buffer, 0, buffer.Length);
+ }
+
+ public void Clear ()
+ {
+ if (_Writer != null)
+ _Writer.Clear ();
+ }
+
+ public void ClearContent ()
+ {
+ Clear();
+ }
+
+ 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 ()
+ {
+ _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;
+
+ Flush ();
+ _bEnded = true;
+ _Context.ApplicationInstance.CompleteRequest ();
+ }
+
+ public void Flush ()
+ {
+ Flush (false);
+ }
+
+ private void Flush (bool bFinish)
+ {
+ if (_bFlushing)
+ 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"];
+ sProto = "HTTP/1.0"; // Remove this line when we support properly
+ // chunked content
+
+ 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) {
+ _WorkerRequest.FlushResponse (bFinish);
+ if (!bFinish)
+ _Writer.Clear ();
+ return;
+ }
+
+ if (!_bSuppressContent && Request.HttpMethod == "HEAD")
+ _bSuppressContent = true;
+
+ 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);
+ }
+ } else {
+ _Writer.Clear ();
+ }
+
+ _WorkerRequest.FlushResponse (bFinish);
+
+ if (!bFinish)
+ _Writer.Clear ();
+ } finally {
+ _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 ();
+ }
+
+ 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);
+ }
+
+ [MonoTODO()]
+ public static void RemoveOutputCacheItem (string path)
+ {
+ throw new NotImplementedException ();
+ }
+
+ 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 ()
+ {
+ }
+ }
+}
+