tags:

views:

100

answers:

4

In C#, is there any built-in way to "correct" URLs that have parent pathing in them? So, I want to take this:

/foo/bar/../baz.html

And turn it into...

/foo/baz.html

(The "bar" directory being negated by the ".." after it in the path.)

I've tried to hand-roll this, but the logic gets pretty ugly, pretty quickly. Consider something like:

/foo1/foo2/../foo3/foo4/foo5/../../bar.html

The path I headed down was to move through the URL, segment by segment, and start writing a new URL. I would only include segment 1 in the new URL, if segment 2 wasn't "..". But, in the case above, I need to "look ahead" and figure out how many parent paths I have coming.

I tried to use Path.GetFullPath, and it technically got it work, but, man, it's ugly. Fair warning: you may want to avert your eyes on this one:

Path.GetFullPath(myUrl).Replace(Path.GetFullPath(@"\"), "").Replace(@"\", "/") + "/";

GetFullPath returns a file system path from the "C:\" root, so you essentially have to replace that too, than convert the slashes, etc.

I can probably bang this out eventually (and my ugly code above technically works), but it strikes me that I can't be the first one to try this. Google did not help.

(The answer in another language would be helpful too -- at least it would show the logic.)

+2  A: 

Try the VirtualPathUtility class. It has some methods that should be able to help here, specifically the ToAbsolute() method, which if memory doesn't fail me, should be able to take an application-relative path and convert it to an application absolute path.

womp
A: 
var fullPath = Path.GetFullPath("/foo1/foo2/../foo3/foo4/foo5/../../bar.html");
var result = fullPath.Replace(Path.GetPathRoot(fullPath), string.Empty).Replace("\\", "/");
Nitin Chaudhari
+6  A: 

This should work for all URLs (including URLs with a QueryString):

var url = "/foo/bar/../bar.html";
var ubuilder = new UriBuilder();
ubuilder.Path = url;
var newURL = ubuilder.Uri.LocalPath;
Sani Huttunen
+1 It uses the System.Uri class to parse the path so it should be pretty safe for web urls. You can even do it in one ugly line: `string normalized = new UriBuilder() { Path = path }.Uri.LocalPath`.
Jaroslav Jandek
@Jaroslav Jandek: Yes indeed you can do it as a oneliner. But as you say it is a bit ugly. ;)
Sani Huttunen
+2  A: 

If you really want to roll your own version, try using a stack:

  1. split path by path separator '/'
  2. loop through segments
    1. push any segment that is not '..' onto a stack
    2. if the segment is '..', pop the stack
  3. join the segments with the path separator '/'

But as others have noted: It is probably better to get your library to do this for you.

Daren Thomas
The OP actually asks for a framework method. Since he was unable to find one he rolled his own but would prefer a built in method..
Sani Huttunen
Sure. In fact, that is exactly why I upvoted you. But OP also mentioned he would like to learn the logic. From his post, I got the feeling he didn't grok using stacks for this kind of problem yet - thought he might learn something while we are at it...
Daren Thomas
Daren: I do want and appreciate the framework solution, but your algorithm there is really good. I wish I would have thought of that at 1 a.m. this morning. I won't upvote because the framework method is "more correct," but nicely done.
Deane
@Daren Thomas: My comment was more a comment on the first sentence in your post. Your solution is good (+1) but from the first sentence I gathered that you thought the OP REALLY wanted to roll his own version. Alas, I was mistaken. :)
Sani Huttunen