// Author:
// Miguel de Icaza (miguel@novell.com)
// Gonzalo Paniagua Javier (gonzalo@ximian.com)
-//
-
//
// Copyright (C) 2005 Novell, Inc (http://www.novell.com)
//
string charset;
bool charset_set;
CachedRawResponse cached_response;
- string cache_control = "private";
+ string user_cache_control = "private";
string redirect_location;
//
// Transfer encoding state
//
string transfer_encoding;
- internal byte [] use_chunked;
+ internal bool use_chunked;
bool closed;
internal bool suppress_content;
//
internal object FlagEnd = new object ();
- internal readonly static byte [] ChunkedNewline = new byte [2] { 13, 10 };
-
internal HttpResponse ()
{
output_stream = new HttpResponseStream (this);
this.context = context;
if (worker_request != null)
- use_chunked = worker_request.GetHttpVersion () == "HTTP/1.1" ? new byte [24] : null;
+ use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
}
internal TextWriter SetTextWriter (TextWriter writer)
}
}
- [MonoTODO]
public Stream Filter {
get {
- throw new NotImplementedException ();
+ if (WorkerRequest == null)
+ return null;
+
+ return output_stream.Filter;
}
set {
- throw new NotImplementedException ();
+ output_stream.Filter = value;
}
}
#if NET_2_0
throw new HttpException ("headers have been already sent");
if (String.Compare (name, "content-length", true, CultureInfo.InvariantCulture) == 0){
- content_length = Int64.Parse (value);
- use_chunked = null;
+ content_length = (long) UInt64.Parse (value);
+ use_chunked = false;
return;
}
if (String.Compare (name, "transfer-encoding", true, CultureInfo.InvariantCulture) == 0){
transfer_encoding = value;
- use_chunked = null;
+ use_chunked = false;
return;
}
if (String.Compare (name, "cache-control", true, CultureInfo.InvariantCulture) == 0){
- cache_control = value;
+ user_cache_control = value;
return;
}
return virtualPath;
}
- internal void SendSize (long l)
- {
- string s = l.ToString ();
- int i;
-
- for (i = 0; i < s.Length; i++){
- use_chunked [i] = (byte) s [i];
- }
- use_chunked [i++] = 13;
- use_chunked [i++] = 10;
-
- WorkerRequest.SendResponseFromMemory (use_chunked, i);
- }
-
public void BinaryWrite (byte [] buffer)
{
- if (this.buffer)
- output_stream.Write (buffer, 0, buffer.Length);
- else {
- if (use_chunked != null)
- SendSize (buffer.Length);
-
- WorkerRequest.SendResponseFromMemory (buffer, buffer.Length);
-
- WorkerRequest.SendResponseFromMemory (ChunkedNewline, 2);
-
- //
- // TODO This hack is for current XSP
- //
- WorkerRequest.FlushResponse (false);
- }
+ output_stream.Write (buffer, 0, buffer.Length);
}
internal void BinaryWrite (byte [] buffer, int start, int len)
content_length = -1;
content_type = "text/html";
transfer_encoding = null;
- cache_control = "private";
+ user_cache_control = null;
headers.Clear ();
}
Thread.CurrentThread.Abort (FlagEnd);
} else {
// If this is called from an async event, signal the completion
- // but don't thow.
+ // but don't throw.
context.ApplicationInstance.CompleteRequest ();
}
}
// Content-Type
// Transfer-Encoding (chunked)
// Cache-Control
- void WriteHeaders (bool final_flush)
+ void AddHeadersNoCache (ArrayList write_headers, bool final_flush)
{
- if (WorkerRequest != null)
- WorkerRequest.SendStatus (status_code, StatusDescription);
-
- if (cached_response != null)
- cached_response.SetHeaders (headers);
-
- // If this page is cached use the cached headers
- // instead of the standard headers
- ArrayList write_headers = headers;
- if (cached_headers != null)
- write_headers = cached_headers;
-
//
// Transfer-Encoding
//
- if (use_chunked != null)
+ if (use_chunked)
write_headers.Add (new UnknownResponseHeader ("Transfer-Encoding", "chunked"));
else if (transfer_encoding != null)
write_headers.Add (new UnknownResponseHeader ("Transfer-Encoding", transfer_encoding));
// We are buffering, and this is a flush in the middle.
// If we are not chunked, we need to set "Connection: close".
//
- if (use_chunked == null){
+ if (use_chunked){
+#if DEBUG
Console.WriteLine ("Setting to close2");
+#endif
write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderConnection, "close"));
}
}
// If the content-length is not set, and we are not buffering, we must
// close at the end.
//
- if (use_chunked == null){
+ if (use_chunked){
+#if DEBUG
Console.WriteLine ("Setting to close");
+#endif
write_headers.Add (new KnownResponseHeader (HttpWorkerRequest.HeaderConnection, "close"));
}
}
if (cache_policy != null)
cache_policy.SetHeaders (this, headers);
else
- write_headers.Add (new UnknownResponseHeader ("Cache-Control", cache_control));
+ write_headers.Add (new UnknownResponseHeader ("Cache-Control", CacheControl));
//
// Content-Type
write_headers.Add (cookies.Get (i).GetCookieHeader ());
}
+ }
+
+ internal void WriteHeaders (bool final_flush)
+ {
+ if (headers_sent)
+ return;
+
+ if (WorkerRequest != null)
+ WorkerRequest.SendStatus (status_code, StatusDescription);
+
+ if (cached_response != null)
+ cached_response.SetHeaders (headers);
+
+ // If this page is cached use the cached headers
+ // instead of the standard headers
+ ArrayList write_headers = headers;
+ if (cached_headers != null)
+ write_headers = cached_headers;
+ else
+ AddHeadersNoCache (write_headers, final_flush);
+
//
// Flush
//
}
headers_sent = true;
}
-
+
+ internal void DoFilter (bool close)
+ {
+ if (output_stream.HaveFilter && context != null && context.Error == null)
+ output_stream.ApplyFilter (close);
+ }
+
internal void Flush (bool final_flush)
{
+ DoFilter (final_flush);
if (!headers_sent){
if (final_flush || status_code != 200)
- use_chunked = null;
-
- WriteHeaders (final_flush);
+ use_chunked = false;
}
bool head = ((context != null) && (context.Request.HttpMethod == "HEAD"));
if (suppress_content || head) {
+ if (!headers_sent)
+ WriteHeaders (true);
output_stream.Clear ();
if (WorkerRequest != null)
- output_stream.Flush (WorkerRequest, final_flush);
+ output_stream.Flush (WorkerRequest, true); // ignore final_flush here.
return;
}
+ if (!headers_sent)
+ WriteHeaders (final_flush);
+
if (context != null) {
HttpApplication app_instance = context.ApplicationInstance;
if (app_instance != null)
}
if (IsCached) {
- byte [] data = output_stream.GetData ();
- cached_response.ContentLength = data.Length;
- cached_response.SetData (data);
+ MemoryStream ms = output_stream.GetData ();
+ cached_response.ContentLength = (int) ms.Length;
+ cached_response.SetData (ms.GetBuffer ());
}
if (WorkerRequest != null)
output_stream.Flush (WorkerRequest, final_flush);
-
- // FIXME
- if (final_flush && use_chunked != null)
- Write ("0\r\n\r\n");
}
public void Flush ()
if (buffer)
return;
+ output_stream.ApplyFilter (false);
Flush ();
}
-#if !TARGET_JVM
+#if TARGET_JVM
+ public void WriteFile (IntPtr fileHandle, long offset, long size) {
+ throw new NotSupportedException("IntPtr not supported");
+ }
+#else
public void WriteFile (IntPtr fileHandle, long offset, long size)
{
if (offset < 0)
if (buffer)
return;
+ output_stream.ApplyFilter (false);
Flush ();
}
#endif
if (buffer)
return;
+ output_stream.ApplyFilter (false);
Flush ();
}
#if NET_2_0
internal void TransmitFile (string filename, bool final_flush)
{
FileInfo fi = new FileInfo (filename);
+ using (Stream s = fi.OpenRead ()); // Just check if we can read.
output_stream.WriteFile (filename, 0, fi.Length);
+ output_stream.ApplyFilter (final_flush);
Flush (final_flush);
}
//
public string CacheControl {
set {
- if (String.Compare (value, "public", true, CultureInfo.InvariantCulture) == 0)
+ if (value == null || value == "") {
+ Cache.SetCacheability (HttpCacheability.NoCache);
+ user_cache_control = null;
+ } else if (String.Compare (value, "public", true, CultureInfo.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.Public);
- else if (String.Compare (value, "private", true, CultureInfo.InvariantCulture) == 0)
+ user_cache_control = "public";
+ } else if (String.Compare (value, "private", true, CultureInfo.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.Private);
- else if (String.Compare (value, "no-cache", true, CultureInfo.InvariantCulture) == 0)
+ user_cache_control = "private";
+ } else if (String.Compare (value, "no-cache", true, CultureInfo.InvariantCulture) == 0) {
Cache.SetCacheability (HttpCacheability.NoCache);
- else
+ user_cache_control = "no-cache";
+ } else
throw new ArgumentException ("CacheControl property only allows `public', " +
"`private' or no-cache, for different uses, use " +
"Response.AppendHeader");
- cache_control = value;
}
- get {
- if ((cache_control == null) && (cache_policy != null)) {
- switch (Cache.Cacheability) {
- case (HttpCacheability)0:
- case HttpCacheability.NoCache:
- return "no-cache";
- case HttpCacheability.Private:
- case HttpCacheability.Server:
- case HttpCacheability.ServerAndPrivate:
- return "private";
- case HttpCacheability.Public:
- return "public";
- default:
- throw new Exception ("Unknown internal state: " + Cache.Cacheability);
- }
- }
- return cache_control;
- }
+ get { return (user_cache_control != null) ? user_cache_control : "private"; }
}
#endregion
+ internal int GetOutputByteCount ()
+ {
+ return output_stream.GetTotalLength ();
+ }
+
internal void ReleaseResources ()
{
- output_stream.ReleaseResources ();
+ output_stream.ReleaseResources (true);
output_stream = null;
}
}
-
}
+