This repository was archived by the owner on Nov 20, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 188
Expand file tree
/
Copy pathPathString.cs
More file actions
282 lines (255 loc) · 11.4 KB
/
PathString.cs
File metadata and controls
282 lines (255 loc) · 11.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.Framework.Internal;
using Microsoft.Framework.WebEncoders;
namespace Microsoft.AspNet.Http
{
/// <summary>
/// Provides correct escaping for Path and PathBase values when needed to reconstruct a request or redirect URI string
/// </summary>
public struct PathString : IEquatable<PathString>
{
/// <summary>
/// Represents the empty path. This field is read-only.
/// </summary>
public static readonly PathString Empty = new PathString(String.Empty);
private readonly string _value;
/// <summary>
/// Initalize the path string with a given value. This value must be in unescaped format. Use
/// PathString.FromUriComponent(value) if you have a path value which is in an escaped format.
/// </summary>
/// <param name="value">The unescaped path to be assigned to the Value property.</param>
public PathString(string value)
{
if (!String.IsNullOrEmpty(value) && value[0] != '/')
{
throw new ArgumentException(""/*Resources.Exception_PathMustStartWithSlash*/, "value");
}
_value = value;
}
/// <summary>
/// The unescaped path value
/// </summary>
public string Value
{
get { return _value; }
}
/// <summary>
/// True if the path is not empty
/// </summary>
public bool HasValue
{
get { return !String.IsNullOrEmpty(_value); }
}
/// <summary>
/// Provides the path string escaped in a way which is correct for combining into the URI representation.
/// </summary>
/// <returns>The escaped path value</returns>
public override string ToString()
{
return ToUriComponent();
}
/// <summary>
/// Provides the path string escaped in a way which is correct for combining into the URI representation.
/// </summary>
/// <returns>The escaped path value</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1055:UriReturnValuesShouldNotBeStrings", Justification = "Purpose of the method is to return a string")]
public string ToUriComponent()
{
// TODO: Measure the cost of this escaping and consider optimizing.
return HasValue ? string.Join("/", _value.Split('/').Select(UrlEncoder.Default.UrlEncode)) : string.Empty;
}
/// <summary>
/// Returns an PathString given the path as it is escaped in the URI format. The string MUST NOT contain any
/// value that is not a path.
/// </summary>
/// <param name="uriComponent">The escaped path as it appears in the URI format.</param>
/// <returns>The resulting PathString</returns>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1057:StringUriOverloadsCallSystemUriOverloads", Justification = "Requirements not compatible with URI processing")]
public static PathString FromUriComponent(string uriComponent)
{
// REVIEW: what is the exactly correct thing to do?
return new PathString(Uri.UnescapeDataString(uriComponent));
}
/// <summary>
/// Returns an PathString given the path as from a Uri object. Relative Uri objects are not supported.
/// </summary>
/// <param name="uri">The Uri object</param>
/// <returns>The resulting PathString</returns>
public static PathString FromUriComponent([NotNull] Uri uri)
{
// REVIEW: what is the exactly correct thing to do?
return new PathString("/" + uri.GetComponents(UriComponents.Path, UriFormat.Unescaped));
}
public bool StartsWithSegments(PathString other)
{
string value1 = Value ?? String.Empty;
string value2 = other.Value ?? String.Empty;
if (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
{
return value1.Length == value2.Length || value1[value2.Length] == '/';
}
return false;
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1021:AvoidOutParameters", MessageId = "1#", Justification = "Secondary information needed after boolean result obtained")]
public bool StartsWithSegments(PathString other, out PathString remaining)
{
string value1 = Value ?? String.Empty;
string value2 = other.Value ?? String.Empty;
if (value1.StartsWith(value2, StringComparison.OrdinalIgnoreCase))
{
if (value1.Length == value2.Length || value1[value2.Length] == '/')
{
remaining = new PathString(value1.Substring(value2.Length));
return true;
}
}
remaining = Empty;
return false;
}
/// <summary>
/// Adds two PathString instances into a combined PathString value.
/// </summary>
/// <returns>The combined PathString value</returns>
public PathString Add(PathString other)
{
if (HasValue &&
other.HasValue &&
Value[Value.Length - 1] == '/')
{
// If the path string has a trailing slash and the other string has a leading slash, we need
// to trim one of them.
return new PathString(Value + other.Value.Substring(1));
}
return new PathString(Value + other.Value);
}
/// <summary>
/// Combines a PathString and QueryString into the joined URI formatted string value.
/// </summary>
/// <returns>The joined URI formatted string value</returns>
public string Add(QueryString other)
{
return ToUriComponent() + other.ToUriComponent();
}
/// <summary>
/// Compares this PathString value to another value. The default comparison is StringComparison.OrdinalIgnoreCase.
/// </summary>
/// <param name="other">The second PathString for comparison.</param>
/// <returns>True if both PathString values are equal</returns>
public bool Equals(PathString other)
{
return string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Compares this PathString value to another value using a specific StringComparison type
/// </summary>
/// <param name="other">The second PathString for comparison</param>
/// <param name="comparisonType">The StringComparison type to use</param>
/// <returns>True if both PathString values are equal</returns>
public bool Equals(PathString other, StringComparison comparisonType)
{
return string.Equals(_value, other._value, comparisonType);
}
/// <summary>
/// Compares this PathString value to another value. The default comparison is StringComparison.OrdinalIgnoreCase.
/// </summary>
/// <param name="obj">The second PathString for comparison.</param>
/// <returns>True if both PathString values are equal</returns>
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj))
{
return false;
}
return obj is PathString && Equals((PathString)obj, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Returns the hash code for the PathString value. The hash code is provided by the OrdinalIgnoreCase implementation.
/// </summary>
/// <returns>The hash code</returns>
public override int GetHashCode()
{
return (_value != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(_value) : 0);
}
/// <summary>
/// Operator call through to Equals
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>True if both PathString values are equal</returns>
public static bool operator ==(PathString left, PathString right)
{
return left.Equals(right, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Operator call through to Equals
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>True if both PathString values are not equal</returns>
public static bool operator !=(PathString left, PathString right)
{
return !left.Equals(right, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>The ToString combination of both values</returns>
public static string operator +(string left, PathString right)
{
// This overload exists to prevent the implicit string<->PathString converter from
// trying to call the PathString+PathString operator for things that are not path strings.
return string.Concat(left, right.ToString());
}
/// <summary>
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>The ToString combination of both values</returns>
public static string operator +(PathString left, string right)
{
// This overload exists to prevent the implicit string<->PathString converter from
// trying to call the PathString+PathString operator for things that are not path strings.
return string.Concat(left.ToString(), right);
}
/// <summary>
/// Operator call through to Add
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>The PathString combination of both values</returns>
public static PathString operator +(PathString left, PathString right)
{
return left.Add(right);
}
/// <summary>
/// Operator call through to Add
/// </summary>
/// <param name="left">The left parameter</param>
/// <param name="right">The right parameter</param>
/// <returns>The PathString combination of both values</returns>
public static string operator +(PathString left, QueryString right)
{
return left.Add(right);
}
/// <summary>
/// Implicitly creates a new PathString from the given string.
/// </summary>
/// <param name="s"></param>
public static implicit operator PathString(string s)
{
return new PathString(s);
}
/// <summary>
/// Implicitly calls ToString().
/// </summary>
/// <param name="path"></param>
public static implicit operator string(PathString path)
{
return path.ToString();
}
}
}