2 * Namespace: System.Web.UI.Util
6 * Maintainer: gvaish@iitk.ac.in
9 * (C) Gaurav Vaish (2001)
13 using System.Collections;
15 using System.Web.SessionState;
17 namespace System.Web.Util
19 internal class UrlUtils
22 * I could not find these functions in the class System.Uri
23 * Besides, an instance of Uri will not be formed until and unless the address is of
24 * the form protocol://[user:pass]host[:port]/[fullpath]
25 * ie, a protocol, and that too without any blanks before,
26 * is a must which may not be the case here.
27 * Important: Escaped URL is assumed here. nothing like .aspx?path=/something
28 * It should be .aspx?path=%2Fsomething
30 public static string GetProtocol(string url)
32 //Taking code from Java Class java.net.URL
38 int i, start = 0, limit;
42 while( (limit > 0) && (url[limit-1] <= ' '))
46 while( (start < limit) && (url[start] <= ' '))
50 if(RegionMatches(true, url, start, "url:", 0, 4))
54 if(start < url.Length && url[start]=='#')
58 for(i = start; !aRef && (i < limit) && ((c=url[i]) != '/'); i++)
62 return url.Substring(start, i - start);
70 public static bool IsRelativeUrl(string url)
72 if (url.IndexOf(':') == -1)
73 return !IsRooted(url);
78 public static bool IsRootUrl(string url)
84 return IsValidProtocol(GetProtocol(url).ToLower());
90 public static bool IsRooted(string path)
92 if(path!=null && path.Length > 0)
94 return (path[0]=='/' || path[0]=='\\');
99 public static void FailIfPhysicalPath(string path)
101 if(path!= null && path.Length > 1)
103 if(path[1]==':' || path.StartsWith(@"\\"))
104 throw new HttpException(HttpRuntime.FormatResourceString("Physical_path_not_allowed", path));
108 public static string Combine (string basePath, string relPath)
111 throw new ArgumentNullException ("relPath");
113 int rlength = relPath.Length;
117 FailIfPhysicalPath (relPath);
118 relPath = relPath.Replace ("\\", "/");
119 if (IsRooted (relPath))
120 return Reduce (relPath);
122 char first = relPath [0];
123 if (rlength < 3 || first == '~' || first == '/' || first == '\\') {
124 if (basePath == null || (basePath.Length == 1 && basePath [0] == '/'))
125 basePath = String.Empty;
127 string slash = (first == '/') ? "" : "/";
131 } else if (rlength > 1 && relPath [1] == '/') {
132 relPath = relPath.Substring (2);
136 return Reduce (HttpRuntime.AppDomainAppVirtualPath + slash + relPath);
139 return Reduce (basePath + slash + relPath);
142 if (basePath == null || basePath == "")
143 basePath = HttpRuntime.AppDomainAppVirtualPath;
145 if (basePath.Length <= 1)
146 basePath = String.Empty;
148 return Reduce (basePath + "/" + relPath);
151 public static bool IsValidProtocol(string protocol)
153 if(protocol.Length < 1)
155 char c = protocol[0];
156 if(!Char.IsLetter(c))
160 for(int i=1; i < protocol.Length; i++)
163 if(!Char.IsLetterOrDigit(c) && c!='.' && c!='+' && c!='-')
172 * MakeRelative("http://www.foo.com/bar1/bar2/file","http://www.foo.com/bar1")
173 * will return "bar2/file"
174 * while MakeRelative("http://www.foo.com/bar1/...","http://www.anotherfoo.com")
175 * return 'null' and so does the call
176 * MakeRelative("http://www.foo.com/bar1/bar2","http://www.foo.com/bar")
178 public static string MakeRelative(string fullUrl, string relativeTo)
180 if (fullUrl == relativeTo)
183 if (fullUrl.IndexOf (relativeTo) != 0)
186 string leftOver = fullUrl.Substring (relativeTo.Length);
187 if (leftOver.Length > 0 && leftOver [0] == '/')
188 leftOver = leftOver.Substring (1);
190 leftOver = Reduce (leftOver);
191 if (leftOver.Length > 0 && leftOver [0] == '/')
192 leftOver = leftOver.Substring (1);
198 * Check JavaDocs for java.lang.String#RegionMatches(bool, int, String, int, int)
199 * Could not find anything similar in the System.String class
201 public static bool RegionMatches(bool ignoreCase, string source, int start, string match, int offset, int len)
203 if(source!=null || match!=null)
205 if(source.Length>0 && match.Length>0)
207 char[] ta = source.ToCharArray();
208 char[] pa = match.ToCharArray();
209 if((offset < 0) || (start < 0) || (start > (source.Length - len)) || (offset > (match.Length - len)))
215 char c1 = ta[start++];
216 char c2 = pa[offset++];
221 if(Char.ToUpper(c1)==Char.ToUpper(c2))
223 // Check for Gregorian Calendar where the above may not hold good
224 if(Char.ToLower(c1)==Char.ToLower(c2))
235 public static string Reduce (string path)
237 path = path.Replace ('\\','/');
239 string [] parts = path.Split ('/');
240 ArrayList result = new ArrayList ();
242 int end = parts.Length;
243 for (int i = 0; i < end; i++) {
244 string current = parts [i];
248 if (current == "..") {
249 if (result.Count == 0) {
250 if (i == 1) // see bug 52599
253 throw new HttpException ("Invalid path.");
256 result.RemoveAt (result.Count - 1);
260 result.Add (current);
263 if (result.Count == 0)
266 return String.Join ("/", (string []) result.ToArray (typeof (string)));
269 public static string GetDirectory(string url)
279 url = url.Replace('\\','/');
282 int last = url.LastIndexOf ('/');
284 baseDir = url.Substring(0, url.LastIndexOf('/'));
286 if(baseDir.Length==0)
293 static string GetFile (string url)
301 url = url.Replace ('\\', '/');
303 int last = url.LastIndexOf ('/') + 1;
305 url = url.Substring (last);
311 public static string InsertSessionId (string id, string path)
313 string dir = GetDirectory (path);
314 if (!dir.EndsWith ("/"))
317 return Reduce (dir + "(" + id + ")/" + GetFile (path));
320 public static string GetSessionId (string path)
322 int len = path.Length;
323 if ((len < SessionId.IdLength + 2) || (path [len - 1] != ')') ||
324 (path [len - SessionId.IdLength - 2] != '('))
327 return path.Substring (len - SessionId.IdLength - 1, SessionId.IdLength);
330 public static string RemoveSessionId (string base_path, string file_path)
332 int len = base_path.Length;
333 string dir = base_path.Substring (0, len - SessionId.IdLength - 2);
334 if (!dir.EndsWith ("/"))
337 return Reduce (dir + GetFile (file_path));
340 public static string ResolveVirtualPathFromAppAbsolute (string path)
342 if (path [0] != '~') return path;
344 if (path.Length == 1)
345 return HttpRuntime.AppDomainAppVirtualPath;
347 if (path [1] == '/' || path [1] == '\\') {
348 string appPath = HttpRuntime.AppDomainAppVirtualPath;
349 if (appPath.Length > 1)
350 return appPath + "/" + path.Substring (2);
351 return "/" + path.Substring (2);
356 public static string ResolvePhysicalPathFromAppAbsolute (string path)
358 if (path [0] != '~') return path;
360 if (path.Length == 1)
361 return HttpRuntime.AppDomainAppPath;
363 if (path [1] == '/' || path [1] == '\\') {
364 string appPath = HttpRuntime.AppDomainAppPath;
365 if (appPath.Length > 1)
366 return appPath + "/" + path.Substring (2);
367 return "/" + path.Substring (2);