3 // Permission is hereby granted, free of charge, to any person obtaining
4 // a copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to
8 // permit persons to whom the Software is furnished to do so, subject to
9 // the following conditions:
11 // The above copyright notice and this permission notice shall be
12 // included in all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 * Namespace: System.Web.UI.Util
26 * Author: Gaurav Vaish
27 * Maintainer: gvaish@iitk.ac.in
30 * (C) Gaurav Vaish (2001)
34 using System.Collections;
36 using System.Web.SessionState;
38 namespace System.Web.Util
40 internal class UrlUtils
43 * I could not find these functions in the class System.Uri
44 * Besides, an instance of Uri will not be formed until and unless the address is of
45 * the form protocol://[user:pass]host[:port]/[fullpath]
46 * ie, a protocol, and that too without any blanks before,
47 * is a must which may not be the case here.
48 * Important: Escaped URL is assumed here. nothing like .aspx?path=/something
49 * It should be .aspx?path=%2Fsomething
51 public static string GetProtocol(string url)
53 //Taking code from Java Class java.net.URL
59 int i, start = 0, limit;
63 while( (limit > 0) && (url[limit-1] <= ' '))
67 while( (start < limit) && (url[start] <= ' '))
71 if(RegionMatches(true, url, start, "url:", 0, 4))
75 if(start < url.Length && url[start]=='#')
79 for(i = start; !aRef && (i < limit) && ((c=url[i]) != '/'); i++)
83 return url.Substring(start, i - start);
91 public static bool IsRelativeUrl(string url)
93 if (url.IndexOf(':') == -1)
94 return !IsRooted(url);
99 public static bool IsRootUrl(string url)
105 return IsValidProtocol(GetProtocol(url).ToLower());
111 public static bool IsRooted(string path)
113 if(path!=null && path.Length > 0)
115 return (path[0]=='/' || path[0]=='\\');
120 public static void FailIfPhysicalPath(string path)
122 if(path!= null && path.Length > 1)
124 if(path[1]==':' || path.StartsWith(@"\\"))
125 throw new HttpException(HttpRuntime.FormatResourceString("Physical_path_not_allowed", path));
129 public static string Combine (string basePath, string relPath)
132 throw new ArgumentNullException ("relPath");
134 int rlength = relPath.Length;
138 FailIfPhysicalPath (relPath);
139 relPath = relPath.Replace ("\\", "/");
140 if (IsRooted (relPath))
141 return Reduce (relPath);
143 char first = relPath [0];
144 if (rlength < 3 || first == '~' || first == '/' || first == '\\') {
145 if (basePath == null || (basePath.Length == 1 && basePath [0] == '/'))
146 basePath = String.Empty;
148 string slash = (first == '/') ? "" : "/";
152 } else if (rlength > 1 && relPath [1] == '/') {
153 relPath = relPath.Substring (2);
157 string appvpath = HttpRuntime.AppDomainAppVirtualPath;
158 if (appvpath.EndsWith ("/"))
161 return Reduce (appvpath + slash + relPath);
164 return Reduce (basePath + slash + relPath);
167 if (basePath == null || basePath == "")
168 basePath = HttpRuntime.AppDomainAppVirtualPath;
170 if (basePath.Length <= 1)
171 basePath = String.Empty;
173 return Reduce (basePath + "/" + relPath);
176 public static bool IsValidProtocol(string protocol)
178 if(protocol.Length < 1)
180 char c = protocol[0];
181 if(!Char.IsLetter(c))
185 for(int i=1; i < protocol.Length; i++)
188 if(!Char.IsLetterOrDigit(c) && c!='.' && c!='+' && c!='-')
197 * MakeRelative("http://www.foo.com/bar1/bar2/file","http://www.foo.com/bar1")
198 * will return "bar2/file"
199 * while MakeRelative("http://www.foo.com/bar1/...","http://www.anotherfoo.com")
200 * return 'null' and so does the call
201 * MakeRelative("http://www.foo.com/bar1/bar2","http://www.foo.com/bar")
203 public static string MakeRelative(string fullUrl, string relativeTo)
205 if (fullUrl == relativeTo)
208 if (fullUrl.IndexOf (relativeTo) != 0)
211 string leftOver = fullUrl.Substring (relativeTo.Length);
212 if (leftOver.Length > 0 && leftOver [0] == '/')
213 leftOver = leftOver.Substring (1);
215 leftOver = Reduce (leftOver);
216 if (leftOver.Length > 0 && leftOver [0] == '/')
217 leftOver = leftOver.Substring (1);
223 * Check JavaDocs for java.lang.String#RegionMatches(bool, int, String, int, int)
224 * Could not find anything similar in the System.String class
226 public static bool RegionMatches(bool ignoreCase, string source, int start, string match, int offset, int len)
228 if(source!=null || match!=null)
230 if(source.Length>0 && match.Length>0)
232 char[] ta = source.ToCharArray();
233 char[] pa = match.ToCharArray();
234 if((offset < 0) || (start < 0) || (start > (source.Length - len)) || (offset > (match.Length - len)))
240 char c1 = ta[start++];
241 char c2 = pa[offset++];
246 if(Char.ToUpper(c1)==Char.ToUpper(c2))
248 // Check for Gregorian Calendar where the above may not hold good
249 if(Char.ToLower(c1)==Char.ToLower(c2))
260 public static string Reduce (string path)
262 path = path.Replace ('\\','/');
264 string [] parts = path.Split ('/');
265 ArrayList result = new ArrayList ();
267 int end = parts.Length;
268 for (int i = 0; i < end; i++) {
269 string current = parts [i];
273 if (current == "..") {
274 if (result.Count == 0) {
275 if (i == 1) // see bug 52599
278 throw new HttpException ("Invalid path.");
281 result.RemoveAt (result.Count - 1);
285 result.Add (current);
288 if (result.Count == 0)
291 return String.Join ("/", (string []) result.ToArray (typeof (string)));
294 public static string GetDirectory(string url)
304 url = url.Replace('\\','/');
307 int last = url.LastIndexOf ('/');
309 baseDir = url.Substring(0, url.LastIndexOf('/'));
311 if(baseDir.Length==0)
318 static string GetFile (string url)
326 url = url.Replace ('\\', '/');
328 int last = url.LastIndexOf ('/') + 1;
330 url = url.Substring (last);
336 // appRoot + SessionID + vpath
337 public static string InsertSessionId (string id, string path)
339 string dir = GetDirectory (path);
340 if (!dir.EndsWith ("/"))
343 string appvpath = HttpRuntime.AppDomainAppVirtualPath;
344 if (!appvpath.EndsWith ("/"))
347 if (path.StartsWith (appvpath))
348 path = path.Substring (appvpath.Length);
351 path = path.Length > 1 ? path.Substring (1) : "";
353 return Reduce (appvpath + "(" + id + ")/" + path);
356 public static string GetSessionId (string path)
358 string appvpath = HttpRuntime.AppDomainAppVirtualPath;
359 if (path.Length <= appvpath.Length)
362 path = path.Substring (appvpath.Length);
363 if (path.Length == 0 || path [0] != '/')
366 int len = path.Length;
367 if ((len < SessionId.IdLength + 3) || (path [1] != '(') ||
368 (path [SessionId.IdLength + 2] != ')'))
371 return path.Substring (2, SessionId.IdLength);
374 public static string RemoveSessionId (string base_path, string file_path)
376 // Caller did a GetSessionId first
377 int idx = base_path.IndexOf ("/(");
378 string dir = base_path.Substring (0, idx + 1);
379 if (!dir.EndsWith ("/"))
382 idx = base_path.IndexOf (")/");
383 if (idx != -1 && base_path.Length > idx + 2) {
384 string dir2 = base_path.Substring (idx + 2);
385 if (!dir2.EndsWith ("/"))
391 return Reduce (dir + GetFile (file_path));
394 public static string ResolveVirtualPathFromAppAbsolute (string path)
396 if (path [0] != '~') return path;
398 if (path.Length == 1)
399 return HttpRuntime.AppDomainAppVirtualPath;
401 if (path [1] == '/' || path [1] == '\\') {
402 string appPath = HttpRuntime.AppDomainAppVirtualPath;
403 if (appPath.Length > 1)
404 return appPath + "/" + path.Substring (2);
405 return "/" + path.Substring (2);
410 public static string ResolvePhysicalPathFromAppAbsolute (string path)
412 if (path [0] != '~') return path;
414 if (path.Length == 1)
415 return HttpRuntime.AppDomainAppPath;
417 if (path [1] == '/' || path [1] == '\\') {
418 string appPath = HttpRuntime.AppDomainAppPath;
419 if (appPath.Length > 1)
420 return appPath + "/" + path.Substring (2);
421 return "/" + path.Substring (2);