Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit e311eaa

Browse files
committed
Add ResolvePaths ext method
1 parent 4a4e587 commit e311eaa

File tree

2 files changed

+81
-0
lines changed

2 files changed

+81
-0
lines changed

src/ServiceStack.Text/PathUtils.cs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.IO;
8+
using System.Linq;
89
using System.Text;
910
using ServiceStack.Text;
1011

@@ -131,6 +132,33 @@ public static string CombineWith(this string path, params object[] thesePaths)
131132
return StringBuilderThreadStatic.ReturnAndFree(sb);
132133
}
133134

135+
public static string ResolvePaths(this string path)
136+
{
137+
if (path == null || path.IndexOfAny("./", "/.") == -1)
138+
return path;
139+
140+
var parts = path.Split('/').ToList();
141+
var combinedPaths = new List<string>();
142+
foreach (var part in parts)
143+
{
144+
if (string.IsNullOrEmpty(part) || part == ".")
145+
continue;
146+
147+
if (part == ".." && combinedPaths.Count > 0)
148+
combinedPaths.RemoveAt(combinedPaths.Count - 1);
149+
else
150+
combinedPaths.Add(part);
151+
}
152+
153+
var resolvedPath = string.Join("/", combinedPaths);
154+
if (path[0] == '/')
155+
resolvedPath = '/' + resolvedPath;
156+
157+
return path[path.Length - 1] == '/'
158+
? resolvedPath + '/'
159+
: resolvedPath;
160+
}
161+
134162
public static string[] ToStrings(object[] thesePaths)
135163
{
136164
var to = new string[thesePaths.Length];
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using NUnit.Framework;
2+
3+
namespace ServiceStack.Text.Tests
4+
{
5+
public class CombinePathTests
6+
{
7+
[Test]
8+
public void Does_combine_paths()
9+
{
10+
Assert.That("/a".CombineWith("b"), Is.EqualTo("/a/b"));
11+
Assert.That("a".CombineWith("b"), Is.EqualTo("a/b"));
12+
Assert.That("/a/b".CombineWith("c"), Is.EqualTo("/a/b/c"));
13+
Assert.That("a/b".CombineWith("c"), Is.EqualTo("a/b/c"));
14+
Assert.That("/a/b".CombineWith("c/d"), Is.EqualTo("/a/b/c/d"));
15+
Assert.That("/a/b".CombineWith("c", "d"), Is.EqualTo("/a/b/c/d"));
16+
17+
Assert.That("http://example.org/a/b".CombineWith("c", "d"), Is.EqualTo("http://example.org/a/b/c/d"));
18+
}
19+
20+
[Test]
21+
public void Does_combine_paths_with_trailing_slashes()
22+
{
23+
Assert.That("/a/".CombineWith("b"), Is.EqualTo("/a/b"));
24+
Assert.That("/a/".CombineWith("b/"), Is.EqualTo("/a/b/"));
25+
Assert.That("a/".CombineWith("/b"), Is.EqualTo("a/b"));
26+
Assert.That("/a/b/".CombineWith("/c/"), Is.EqualTo("/a/b/c/"));
27+
Assert.That("a/b/".CombineWith("c"), Is.EqualTo("a/b/c"));
28+
Assert.That("/a/b/".CombineWith("/c/d"), Is.EqualTo("/a/b/c/d"));
29+
Assert.That("/a/b/".CombineWith("/c", "/d"), Is.EqualTo("/a/b/c/d"));
30+
31+
Assert.That("http://example.org/a/b/".CombineWith("/c/", "/d"), Is.EqualTo("http://example.org/a/b/c/d"));
32+
}
33+
34+
[Test]
35+
public void Can_resolve_paths()
36+
{
37+
Assert.That("/a/b/../".ResolvePaths(), Is.EqualTo("/a/"));
38+
Assert.That("/a/b/..".ResolvePaths(), Is.EqualTo("/a"));
39+
Assert.That("a/b/..".ResolvePaths(), Is.EqualTo("a"));
40+
41+
Assert.That("a/../b".ResolvePaths(), Is.EqualTo("b"));
42+
Assert.That("a/../b/./c".ResolvePaths(), Is.EqualTo("b/c"));
43+
Assert.That("a/b/c/d/../..".ResolvePaths(), Is.EqualTo("a/b"));
44+
Assert.That("a/b/../../c/d".ResolvePaths(), Is.EqualTo("c/d"));
45+
46+
Assert.That("a/..".ResolvePaths(), Is.EqualTo(""));
47+
Assert.That("a/../..".ResolvePaths(), Is.EqualTo(".."));
48+
Assert.That("a/../../".ResolvePaths(), Is.EqualTo("../"));
49+
Assert.That("a/../../b".ResolvePaths(), Is.EqualTo("../b"));
50+
}
51+
52+
}
53+
}

0 commit comments

Comments
 (0)