initial implementation of 'unify request'
[mono.git] / mcs / class / System.Web / System.Web / HttpRequest.cs
index d374d5c60cf1cff766b16ce548aaadb9135255ec..16e12ff59b22d88a18c10e6de2d172583c427813 100644 (file)
@@ -95,6 +95,8 @@ namespace System.Web {
                bool validate_cookies, validate_query_string, validate_form;
                bool checked_cookies, checked_query_string, checked_form;
 
+               readonly static char [] queryTrimChars = {'?'};
+               
                static HttpRequest ()
                {
                        host_addresses = GetLocalHostAddresses ();
@@ -110,36 +112,96 @@ namespace System.Web {
                        url_components = new UriBuilder (url);
                        url_components.Query = queryString;
                        
-                       query_string_nvc = new WebROCollection ();                                      
-                       HttpUtility.ParseQueryString (queryString, Encoding.Default, query_string_nvc);
+                       query_string_nvc = new WebROCollection ();
+                       if (queryString != null)
+                               HttpUtility.ParseQueryString (queryString, Encoding.Default, query_string_nvc);
                        query_string_nvc.Protect ();
                }
 
+               internal HttpRequest (HttpWorkerRequest worker_request, HttpContext context)
+               {
+                       this.worker_request = worker_request;
+                       this.context = context;
+               }
+               
                UriBuilder UrlComponents {
                        get {
                                if (url_components == null) {
-                                       url_components = new UriBuilder ();
-                                       url_components.Scheme = worker_request.GetProtocol ();
-                                       url_components.Host = worker_request.GetServerName ();
-                                       url_components.Port = worker_request.GetLocalPort ();
-                                       url_components.Path = worker_request.GetUriPath ();
-                                       
+                                       string query;
                                        byte[] queryStringRaw = worker_request.GetQueryStringRawBytes();
                                        if(queryStringRaw != null)
-                                               url_components.Query = ContentEncoding.GetString(queryStringRaw);
+                                               query = ContentEncoding.GetString(queryStringRaw);
                                        else
-                                               url_components.Query = worker_request.GetQueryString();
+                                               query = worker_request.GetQueryString();
+                                       
+                                       BuildUrlComponents (
+#if NET_2_0
+                                               ApplyUrlMapping (worker_request.GetUriPath ()),
+#else
+                                               worker_request.GetUriPath (),
+#endif
+                                               query);
                                }
                                return url_components;
                        }
                }
-               
-               internal HttpRequest (HttpWorkerRequest worker_request, HttpContext context)
+
+               void BuildUrlComponents (string path, string query)
                {
-                       this.worker_request = worker_request;
-                       this.context = context;
+                       if (url_components != null)
+                               return;
+                       url_components = new UriBuilder ();
+                       url_components.Scheme = worker_request.GetProtocol ();
+                       url_components.Host = worker_request.GetServerName ();
+                       url_components.Port = worker_request.GetLocalPort ();
+                       url_components.Path = path;
+                       if (query != null && query.Length > 0)
+                               url_components.Query = query.TrimStart (queryTrimChars);
                }
 
+#if NET_2_0
+               internal string ApplyUrlMapping (string url)
+               {
+                       if (WebConfigurationManager.HasConfigErrors)
+                               return url;
+                       
+                       UrlMappingsSection ums = WebConfigurationManager.GetSection ("system.web/urlMappings", ApplicationPath) as UrlMappingsSection;
+                       UrlMappingCollection umc;
+
+                       if (ums == null || !ums.IsEnabled || (umc = ums.UrlMappings).Count == 0)
+                               return url;
+
+                       string relUrl = VirtualPathUtility.ToAppRelative (url);
+                       UrlMapping um = null;
+                       
+                       foreach (UrlMapping u in umc) {
+                               if (u == null)
+                                       continue;
+                               if (String.Compare (relUrl, u.Url, StringComparison.Ordinal) == 0) {
+                                       um = u;
+                                       break;
+                               }
+                       }
+
+                       if (um == null)
+                               return url;
+
+                       string rawUrl = VirtualPathUtility.ToAbsolute (um.MappedUrl.Trim ());
+                       Uri newUrl = new Uri ("http://host.com" + rawUrl);
+
+                       if (url_components != null) {
+                               url_components.Path = newUrl.AbsolutePath;
+                               url_components.Query = newUrl.Query.TrimStart (queryTrimChars);
+                               query_string_nvc = new WebROCollection ();
+                               HttpUtility.ParseQueryString (newUrl.Query, Encoding.Default, query_string_nvc);
+                               query_string_nvc.Protect ();
+                       } else
+                               BuildUrlComponents (newUrl.AbsolutePath, newUrl.Query);
+
+                       return url_components.Path;
+               }
+#endif
+
                string [] SplitHeader (int header_index)
                {
                        string [] result = null;
@@ -343,7 +405,13 @@ namespace System.Web {
                                        return "/"; // required for 2.0
 
                                if (file_path == null)
-                                       file_path = UrlUtils.Canonic (worker_request.GetFilePath ());
+                                       file_path = UrlUtils.Canonic (
+#if NET_2_0
+                                               ApplyUrlMapping (worker_request.GetFilePath ())
+#else
+                                               worker_request.GetFilePath ()
+#endif
+                                       );
 
                                return file_path;
                        }
@@ -460,7 +528,8 @@ namespace System.Web {
                //
                void AddRawKeyValue (StringBuilder key, StringBuilder value)
                {
-                       form.Add (HttpUtility.UrlDecode (key.ToString (), ContentEncoding),
+                       string decodedKey = HttpUtility.UrlDecode (key.ToString (), ContentEncoding);
+                       form.Add (decodedKey,
                                  HttpUtility.UrlDecode (value.ToString (), ContentEncoding));
 
                        key.Length = 0;
@@ -522,10 +591,14 @@ namespace System.Web {
                                        form = new WebROCollection ();
                                        files = new HttpFileCollection ();
 
-                                       if (IsContentType ("application/x-www-form-urlencoded", true))
-                                               LoadWwwForm ();
-                                       else if (IsContentType ("multipart/form-data", true))
+                                       if (IsContentType ("multipart/form-data", true))
                                                LoadMultiPart ();
+                                       else if (
+#if TARGET_J2EE
+                                               Context.IsPortletRequest ||
+#endif
+                                               IsContentType ("application/x-www-form-urlencoded", true))
+                                               LoadWwwForm ();
 
                                        form.Protect ();
                                }
@@ -541,34 +614,9 @@ namespace System.Web {
 
                public NameValueCollection Headers {
                        get {
-                               if (headers == null){
-                                       headers = new WebROCollection ();
-                                       if (worker_request == null) {
-                                               headers.Protect ();
-                                               return headers;
-                                       }
-
-                                       for (int i = 0; i < HttpWorkerRequest.RequestHeaderMaximum; i++){
-                                               string hval = worker_request.GetKnownRequestHeader (i);
-
-                                               if (hval == null || hval == "")
-                                                       continue;
-                                               
-                                               headers.Add (HttpWorkerRequest.GetKnownRequestHeaderName (i), hval);
-                                       }
+                               if (headers == null)
+                                       headers = new HeadersCollection (this);
                                
-                                       string [][] unknown = worker_request.GetUnknownRequestHeaders ();
-                                       if (unknown != null && unknown.GetUpperBound (0) != -1){
-                                               int top = unknown.GetUpperBound (0) + 1;
-                                               
-                                               for (int i = 0; i < top; i++){
-                                                       // should check if unknown [i] is not null, but MS does not. 
-                                                       
-                                                       headers.Add (unknown [i][0], unknown [i][1]);
-                                               }
-                                       }
-                                       headers.Protect ();
-                               }
                                return headers;
                        }
                }
@@ -585,6 +633,27 @@ namespace System.Web {
                        }
                }
 
+               void DoFilter (byte [] buffer)
+               {
+                       if (input_filter == null || filter == null)
+                               return;
+
+                       if (buffer.Length < 1024)
+                               buffer = new byte [1024];
+
+                       // Replace the input with the filtered input
+                       input_filter.BaseStream = input_stream;
+                       MemoryStream ms = new MemoryStream ();
+                       while (true) {
+                               int n = filter.Read (buffer, 0, buffer.Length);
+                               if (n <= 0)
+                                       break;
+                               ms.Write (buffer, 0, n);
+                       }
+                       // From now on input_stream has the filtered input
+                       input_stream = new MemoryStream (ms.GetBuffer (), 0, (int) ms.Length, false, true);
+               }
+
 #if !TARGET_JVM
                const int INPUT_BUFFER_SIZE = 32*1024;
 
@@ -611,27 +680,6 @@ namespace System.Web {
                        return f;
                }
 
-               void DoFilter (byte [] buffer)
-               {
-                       if (input_filter == null || filter == null)
-                               return;
-
-                       if (buffer.Length < 1024)
-                               buffer = new byte [1024];
-
-                       // Replace the input with the filtered input
-                       input_filter.BaseStream = input_stream;
-                       MemoryStream ms = new MemoryStream ();
-                       while (true) {
-                               int n = filter.Read (buffer, 0, buffer.Length);
-                               if (n <= 0)
-                                       break;
-                               ms.Write (buffer, 0, n);
-                       }
-                       // From now on input_stream has the filtered input
-                       input_stream = new MemoryStream (ms.GetBuffer (), 0, (int) ms.Length, false, true);
-               }
-
                void MakeInputStream ()
                {
                        if (input_stream != null)
@@ -833,21 +881,8 @@ namespace System.Web {
                public NameValueCollection Params {
                        [AspNetHostingPermission (SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Low)]
                        get {
-                               if (all_params == null) {
-                                       all_params = new WebROCollection ();
-
-                                       all_params.Add (QueryString);
-
-                                       /* special handling for Cookies since
-                                        * it isn't a NameValueCollection. */
-                                       foreach (string key in Cookies.AllKeys) {
-                                               all_params.Add (key, Cookies[key].Value);
-                                       }
-
-                                       all_params.Add (Form);
-                                       all_params.Add (ServerVariables);
-                                       all_params.Protect ();
-                               }
+                               if (all_params == null)
+                                       all_params = new HttpParamsCollection (QueryString, Form, ServerVariables, Cookies);
 
                                return all_params;
                        }
@@ -855,12 +890,27 @@ namespace System.Web {
 
                public string Path {
                        get {
-                               if (unescaped_path == null)
+                               if (unescaped_path == null) {
+                                       string path;
+                                       if (url_components != null) {
+                                               // use only if it's already been instantiated, so that we can't go into endless
+                                               // recursion in some scenarios
+                                               path = UrlComponents.Path;
+                                       } else {
 #if NET_2_0
-                                       unescaped_path = Uri.UnescapeDataString (UrlComponents.Path);
+                                               path = ApplyUrlMapping (worker_request.GetUriPath ());
 #else
-                                       unescaped_path = HttpUtility.UrlDecode (UrlComponents.Path);
+                                               path = worker_request.GetUriPath ();
 #endif
+                                       }
+                                               
+#if NET_2_0
+                                       unescaped_path = Uri.UnescapeDataString (path);
+#else
+                                       unescaped_path = HttpUtility.UrlDecode (path);
+#endif
+                               }
+                               
                                return unescaped_path;
                        }
                }
@@ -924,13 +974,16 @@ namespace System.Web {
 
                public NameValueCollection QueryString {
                        get {
-                               if (query_string_nvc == null){
+                               if (query_string_nvc == null) {
+                                       query_string_nvc = new WebROCollection ();
                                        string q = UrlComponents.Query;
-                                       if (q.Length != 0)
-                                               q = q.Remove(0, 1);
-
-                                       query_string_nvc = new WebROCollection ();                                      
-                                       HttpUtility.ParseQueryString (q, ContentEncoding, query_string_nvc);
+                                       if (q != null) {
+                                               if (q.Length != 0)
+                                                       q = q.Remove(0, 1);
+                                       
+                                               HttpUtility.ParseQueryString (q, ContentEncoding, query_string_nvc);
+                                       }
+                                       
                                        query_string_nvc.Protect();
                                }
                                
@@ -996,7 +1049,7 @@ namespace System.Web {
                                        if (orig_url == null)
                                                cached_url = UrlComponents.Uri;
                                        else
-                                               cached_url = new Uri (orig_url); 
+                                               cached_url = new Uri (orig_url);
                                }
 
                                return cached_url;                      
@@ -1122,8 +1175,7 @@ namespace System.Web {
                        }
 
                        if (virtualPath.IndexOf (':') != -1)
-                               throw new ArgumentNullException (
-                                       String.Format ("MapPath: Invalid path '{0}', only virtual paths are accepted", virtualPath));
+                               throw new HttpException (String.Format ("'{0}' is not a valid virtual path.", virtualPath));
 
                        string appVirtualPath = HttpRuntime.AppDomainAppVirtualPath;
 
@@ -1223,10 +1275,16 @@ namespace System.Web {
                        get {
                                string address = worker_request.GetRemoteAddress ();
 
+                               if (StrUtils.IsNullOrEmpty (address))
+                                       return false;
+
                                if (address == "127.0.0.1")
                                        return true;
 
                                System.Net.IPAddress remoteAddr = System.Net.IPAddress.Parse (address);
+                               if (System.Net.IPAddress.IsLoopback (remoteAddr))
+                                       return true;
+
                                for (int i = 0; i < host_addresses.Length; i++)
                                        if (remoteAddr.Equals (host_addresses [i]))
                                                return true;
@@ -1617,7 +1675,7 @@ namespace System.Web {
                        while ((header = ReadHeaders ()) != null) {
                                if (StrUtils.StartsWith (header, "Content-Disposition:", true)) {
                                        elem.Name = GetContentDispositionAttribute (header, "name");
-                                       elem.Filename = GetContentDispositionAttributeWithEncoding (header, "filename");      
+                                       elem.Filename = StripPath (GetContentDispositionAttributeWithEncoding (header, "filename"));
                                } else if (StrUtils.StartsWith (header, "Content-Type:", true)) {
                                        elem.ContentType = header.Substring ("Content-Type:".Length).Trim ();
                                }
@@ -1632,7 +1690,16 @@ namespace System.Web {
                        elem.Length = pos - start;
                        return elem;
                }
-               
+
+               static string StripPath (string path)
+               {
+                       if (path == null || path.Length == 0)
+                               return path;
+                       
+                       if (path.IndexOf (":\\") != 1)
+                               return path;
+                       return path.Substring (path.LastIndexOf ("\\") + 1);
+               }
        }
 #endregion
 }