Merge pull request #901 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / System.Web / System.Web / HttpResponse.cs
index 19dd29da7bd35fd130608826b652321b03a780e5..053d20c9c58b9baa0a741ee35ea327dbf1a9ae48 100644 (file)
@@ -7,7 +7,7 @@
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
 //      Marek Habersack <mhabersack@novell.com>
 //
-// Copyright (C) 2005-2009 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
@@ -88,7 +88,7 @@ namespace System.Web
                // the headers that we compute here.
                //
 
-               NameValueCollection headers;
+               HttpHeaderCollection headers;
                bool headers_sent;
                NameValueCollection cached_headers;
 
@@ -99,6 +99,7 @@ namespace System.Web
                internal bool use_chunked;
                
                bool closed;
+               bool completed;
                internal bool suppress_content;
 
                //
@@ -126,8 +127,13 @@ namespace System.Web
                        this.context = context;
 
 #if !TARGET_J2EE
-                       if (worker_request != null)
-                               use_chunked = (worker_request.GetHttpVersion () == "HTTP/1.1");
+                       if (worker_request != null && worker_request.GetHttpVersion () == "HTTP/1.1") {
+                               string gi = worker_request.GetServerVariable ("GATEWAY_INTERFACE");
+                               use_chunked = (String.IsNullOrEmpty (gi) ||
+                                       !gi.StartsWith ("cgi", StringComparison.OrdinalIgnoreCase));
+                       } else {
+                               use_chunked = false;
+                       }
 #endif
                        writer = new HttpWriter (this);
                }
@@ -143,7 +149,7 @@ namespace System.Web
                        get {
                                if (!version_header_checked && version_header == null) {
                                        version_header_checked = true;
-                                       HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+                                       HttpRuntimeSection config = HttpRuntime.Section;
                                        if (config != null && config.EnableVersionHeader)
                                                version_header = Environment.Version.ToString (3);
                                }
@@ -151,7 +157,12 @@ namespace System.Web
                                return version_header;
                        }
                }
-               
+
+               internal HttpContext Context {
+                       get { return context; }
+                       set { context = value; }
+               }
+                       
                internal string[] FileDependencies {
                        get {
                                if (fileDependencies == null || fileDependencies.Count == 0)
@@ -319,7 +330,7 @@ namespace System.Web
                public NameValueCollection Headers {
                        get {
                                if (headers == null)
-                                       headers = new NameValueCollection ();
+                                       headers = new HttpHeaderCollection ();
 
                                return headers;
                        }
@@ -497,30 +508,29 @@ namespace System.Web
                public void AppendHeader (string name, string value)
                {
                        if (headers_sent)
-                               throw new HttpException ("headers have been already sent");
-                       
+                               throw new HttpException ("Headers have been already sent");
 #if !TARGET_J2EE
-                       if (String.Compare (name, "content-length", true, Helpers.InvariantCulture) == 0){
+                       if (String.Compare (name, "content-length", StringComparison.OrdinalIgnoreCase) == 0){
                                content_length = (long) UInt64.Parse (value);
                                use_chunked = false;
                                return;
                        }
 #endif
 
-                       if (String.Compare (name, "content-type", true, Helpers.InvariantCulture) == 0){
+                       if (String.Compare (name, "content-type", StringComparison.OrdinalIgnoreCase) == 0){
                                ContentType = value;
                                return;
                        }
 
 #if !TARGET_J2EE
-                       if (String.Compare (name, "transfer-encoding", true, Helpers.InvariantCulture) == 0){
+                       if (String.Compare (name, "transfer-encoding", StringComparison.OrdinalIgnoreCase) == 0){
                                transfer_encoding = value;
                                use_chunked = false;
                                return;
                        }
 #endif
 
-                       if (String.Compare (name, "cache-control", true, Helpers.InvariantCulture) == 0){
+                       if (String.Compare (name, "cache-control", StringComparison.OrdinalIgnoreCase) == 0){
                                user_cache_control = value;
                                return;
                        }
@@ -537,7 +547,7 @@ namespace System.Web
                
                public string ApplyAppPathModifier (string virtualPath)
                {
-                       if (virtualPath == null)
+                       if (virtualPath == null || context == null)
                                return null;
                
                        if (virtualPath.Length == 0)
@@ -797,6 +807,9 @@ namespace System.Web
 
                internal void Flush (bool final_flush)
                {
+                       if (completed)
+                               throw new HttpException ("Server cannot flush a completed response");
+                       
                        DoFilter (final_flush);
                        if (!headers_sent){
                                if (final_flush || status_code != 200)
@@ -810,9 +823,11 @@ namespace System.Web
                                output_stream.Clear ();
                                if (WorkerRequest != null)
                                        output_stream.Flush (WorkerRequest, true); // ignore final_flush here.
+                               completed = true;
                                return;
                        }
-
+                       completed = final_flush;
+                       
                        if (!headers_sent)
                                WriteHeaders (final_flush);
 
@@ -867,13 +882,19 @@ namespace System.Web
                                isFullyQualified = false;
 
                        if (!isFullyQualified) {
-                               HttpRuntimeSection config = WebConfigurationManager.GetWebApplicationSection ("system.web/httpRuntime") as HttpRuntimeSection;
+                               HttpRuntimeSection config = HttpRuntime.Section;
                                if (config != null && config.UseFullyQualifiedRedirectUrl) {
                                        var ub = new UriBuilder (context.Request.Url);
-                                       ub.Path = url;
+                                       int qpos = url.IndexOf ('?');
+                                       if (qpos == -1) {
+                                               ub.Path = url;
+                                               ub.Query = null;
+                                       } else {
+                                               ub.Path = url.Substring (0, qpos);
+                                               ub.Query = url.Substring (qpos + 1);
+                                       }
                                        ub.Fragment = null;
                                        ub.Password = null;
-                                       ub.Query = null;
                                        ub.UserName = null;
                                        url = ub.Uri.ToString ();
                                }
@@ -1067,6 +1088,37 @@ namespace System.Web
                        writer.Write (buffer, index, count);
                }
 
+               bool IsFileSystemDirSeparator (char ch)
+               {
+                       return ch == '\\' || ch == '/';
+               }
+               
+               string GetNormalizedFileName (string fn)
+               {
+                       if (String.IsNullOrEmpty (fn))
+                               return fn;
+
+                       // On Linux we don't change \ to / since filenames with \ are valid. We also
+                       // don't remove drive: designator for the same reason.
+                       int len = fn.Length;
+                       if (len >= 3 && fn [1] == ':' && IsFileSystemDirSeparator (fn [2]))
+                               return Path.GetFullPath (fn); // drive-qualified absolute file path
+
+                       bool startsWithDirSeparator = IsFileSystemDirSeparator (fn [0]);
+                       if (len >= 2 && startsWithDirSeparator && IsFileSystemDirSeparator (fn [1]))
+                               return Path.GetFullPath (fn); // UNC path
+
+                       if (!startsWithDirSeparator) {
+                               HttpContext ctx = context ?? HttpContext.Current;
+                               HttpRequest req = ctx != null ? ctx.Request : null;
+                               
+                               if (req != null)
+                                       return req.MapPath (fn);
+                       }
+                       
+                       return fn; // Or should we rather throw?
+               }
+               
                internal void WriteFile (FileStream fs, long offset, long size)
                {
                        byte [] buffer = new byte [32*1024];
@@ -1092,12 +1144,13 @@ namespace System.Web
                        if (filename == null)
                                throw new ArgumentNullException ("filename");
 
+                       string fn = GetNormalizedFileName (filename);
                        if (readIntoMemory){
-                               using (FileStream fs = File.OpenRead (filename))
+                               using (FileStream fs = File.OpenRead (fn))
                                        WriteFile (fs, 0, fs.Length);
                        } else {
-                               FileInfo fi = new FileInfo (filename);
-                               output_stream.WriteFile (filename, 0, fi.Length);
+                               FileInfo fi = new FileInfo (fn);
+                               output_stream.WriteFile (fn, 0, fi.Length);
                        }
                        if (buffer)
                                return;
@@ -1317,8 +1370,13 @@ namespace System.Web
 
                internal void ReleaseResources ()
                {
-                       output_stream.ReleaseResources (true);
-                       output_stream = null;
+                       if (output_stream != null)
+                               output_stream.ReleaseResources (true);
+                       if (completed)
+                               return;
+                       
+                       Close ();
+                       completed = true;
                }
        }