Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Commit 855dd87

Browse files
author
Justin Kotalik
committed
Addresses #678 and #679
1 parent e320755 commit 855dd87

File tree

8 files changed

+243
-8
lines changed

8 files changed

+243
-8
lines changed

Diff for: src/Microsoft.AspNetCore.Http.Abstractions/FragmentString.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -107,21 +107,25 @@ public static FragmentString FromUriComponent(Uri uri)
107107

108108
public bool Equals(FragmentString other)
109109
{
110-
return string.Equals(_value, other._value);
110+
if (!HasValue && !other.HasValue)
111+
{
112+
return true;
113+
}
114+
return string.Equals(_value, other._value, StringComparison.Ordinal);
111115
}
112116

113117
public override bool Equals(object obj)
114118
{
115119
if (ReferenceEquals(null, obj))
116120
{
117-
return false;
121+
return !HasValue;
118122
}
119123
return obj is FragmentString && Equals((FragmentString)obj);
120124
}
121125

122126
public override int GetHashCode()
123127
{
124-
return (_value != null ? _value.GetHashCode() : 0);
128+
return (!HasValue ? _value.GetHashCode() : 0);
125129
}
126130

127131
public static bool operator ==(FragmentString left, FragmentString right)

Diff for: src/Microsoft.AspNetCore.Http.Abstractions/HostString.cs

+6-2
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ public static HostString FromUriComponent(Uri uri)
205205
/// <returns></returns>
206206
public bool Equals(HostString other)
207207
{
208+
if (!HasValue && !other.HasValue)
209+
{
210+
return true;
211+
}
208212
return string.Equals(_value, other._value, StringComparison.OrdinalIgnoreCase);
209213
}
210214

@@ -217,7 +221,7 @@ public override bool Equals(object obj)
217221
{
218222
if (ReferenceEquals(null, obj))
219223
{
220-
return false;
224+
return !HasValue;
221225
}
222226
return obj is HostString && Equals((HostString)obj);
223227
}
@@ -228,7 +232,7 @@ public override bool Equals(object obj)
228232
/// <returns></returns>
229233
public override int GetHashCode()
230234
{
231-
return (_value != null ? StringComparer.OrdinalIgnoreCase.GetHashCode(_value) : 0);
235+
return (!HasValue ? StringComparer.OrdinalIgnoreCase.GetHashCode(_value) : 0);
232236
}
233237

234238
/// <summary>

Diff for: src/Microsoft.AspNetCore.Http.Abstractions/QueryString.cs

+7-3
Original file line numberDiff line numberDiff line change
@@ -215,21 +215,25 @@ public QueryString Add(string name, string value)
215215

216216
public bool Equals(QueryString other)
217217
{
218-
return string.Equals(_value, other._value);
218+
if (!HasValue && !other.HasValue)
219+
{
220+
return true;
221+
}
222+
return string.Equals(_value, other._value, StringComparison.Ordinal);
219223
}
220224

221225
public override bool Equals(object obj)
222226
{
223227
if (ReferenceEquals(null, obj))
224228
{
225-
return false;
229+
return !HasValue;
226230
}
227231
return obj is QueryString && Equals((QueryString)obj);
228232
}
229233

230234
public override int GetHashCode()
231235
{
232-
return _value?.GetHashCode() ?? 0;
236+
return (HasValue ? _value.GetHashCode() : 0);
233237
}
234238

235239
public static bool operator ==(QueryString left, QueryString right)

Diff for: src/Microsoft.AspNetCore.Http.Extensions/UriHelper.cs

+88
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ namespace Microsoft.AspNetCore.Http.Extensions
1111
/// </summary>
1212
public static class UriHelper
1313
{
14+
private const string ForwardSlash = "/";
15+
private const string Pound = "#";
16+
private const string QuestionMark = "?";
1417
private const string SchemeDelimiter = "://";
1518

1619
/// <summary>
@@ -70,6 +73,91 @@ public static string BuildAbsolute(
7073
.ToString();
7174
}
7275

76+
/// <summary>
77+
/// Seperates the given absolute URI string into components. Assumes no PathBase.
78+
/// </summary>
79+
/// <param name="uri">A string representation of the uri.</param>
80+
/// <param name="scheme">http, https, etc.</param>
81+
/// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param>
82+
/// <param name="path">The portion of the request path that identifies the requested resource.</param>
83+
/// <param name="query">The query, if any.</param>
84+
/// <param name="fragment">The fragment, if any.</param>
85+
public static void FromAbsolute(
86+
string uri,
87+
out string scheme,
88+
out HostString host,
89+
out PathString path,
90+
out QueryString query,
91+
out FragmentString fragment)
92+
{
93+
if (uri == null)
94+
{
95+
throw new ArgumentNullException(nameof(uri));
96+
}
97+
98+
// Satisfy the out parameters
99+
path = new PathString();
100+
query = new QueryString();
101+
fragment = new FragmentString();
102+
103+
var schemeIndex = uri.IndexOf(SchemeDelimiter);
104+
if (schemeIndex < 0)
105+
{
106+
throw new FormatException("No scheme delimiter in uri.");
107+
}
108+
109+
scheme = uri.Substring(0, schemeIndex);
110+
111+
// PERF: Calculate the end of the scheme for next IndexOf
112+
schemeIndex += SchemeDelimiter.Length;
113+
114+
// TODO Discuss URI without path/pathbase but with query/fragment
115+
var hostIndex = uri.IndexOf(ForwardSlash, schemeIndex);
116+
117+
if (hostIndex < 0)
118+
{
119+
// Ex: http://example.com
120+
host = new HostString(uri.Substring(schemeIndex));
121+
return;
122+
}
123+
124+
// if trailing slash (http://example.com/, PathString will be created with slash, which is fine.
125+
host = new HostString(uri.Substring(schemeIndex, hostIndex - schemeIndex));
126+
127+
var pathIndex = uri.IndexOf(QuestionMark, hostIndex);
128+
129+
if (pathIndex < 0)
130+
{
131+
// Means there is no query, look for fragment.
132+
pathIndex = uri.IndexOf(Pound, hostIndex);
133+
if (pathIndex < 0)
134+
{
135+
// no fragment, create PathString out of rest of uri
136+
path = new PathString(uri.Substring(hostIndex));
137+
}
138+
else
139+
{
140+
// make new PathString and FragmentString at found index
141+
path = new PathString(uri.Substring(hostIndex, pathIndex - hostIndex));
142+
fragment = new FragmentString(uri.Substring(pathIndex));
143+
}
144+
return;
145+
}
146+
147+
path = new PathString(uri.Substring(hostIndex, pathIndex - hostIndex));
148+
149+
var queryIndex = uri.IndexOf(Pound, pathIndex);
150+
if (queryIndex < 0)
151+
{
152+
// no fragment, create QueryString out of rest of uri
153+
query = new QueryString(uri.Substring(pathIndex));
154+
return;
155+
}
156+
// make new QueryString and FragmentString at found index
157+
query = new QueryString(uri.Substring(pathIndex, queryIndex - pathIndex));
158+
fragment = new FragmentString(uri.Substring(queryIndex));
159+
}
160+
73161
/// <summary>
74162
/// Generates a string from the given absolute or relative Uri that is appropriately encoded for use in
75163
/// HTTP headers. Note that a unicode host name will be encoded as punycode.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using Xunit;
5+
6+
namespace Microsoft.AspNetCore.Http.Abstractions.Tests
7+
{
8+
public class FragmentStringTests
9+
{
10+
[Fact]
11+
public void Equals_EmptyFragmentStringAndDefaultFragmentString()
12+
{
13+
// Act and Assert
14+
Assert.Equal(FragmentString.Empty, default(FragmentString));
15+
Assert.Equal(default(FragmentString), FragmentString.Empty);
16+
Assert.True(FragmentString.Empty == default(FragmentString));
17+
Assert.True(default(FragmentString) == FragmentString.Empty);
18+
Assert.True(FragmentString.Empty.Equals(default(FragmentString)));
19+
Assert.True(default(FragmentString).Equals(FragmentString.Empty));
20+
}
21+
22+
[Fact]
23+
public void NotEquals_DefaultFragmentStringAndNonNullFragmentString()
24+
{
25+
// Arrange
26+
var fragmentString = new FragmentString("#col=1");
27+
28+
// Act and Assert
29+
Assert.NotEqual(fragmentString, default(FragmentString));
30+
}
31+
32+
[Fact]
33+
public void NotEquals_EmptyFragmentStringAndNonNullFragmentString()
34+
{
35+
// Arrange
36+
var fragmentString = new FragmentString("#col=1");
37+
38+
// Act and Assert
39+
Assert.NotEqual(fragmentString, FragmentString.Empty);
40+
}
41+
}
42+
}

Diff for: test/Microsoft.AspNetCore.Http.Abstractions.Tests/HostStringTest.cs

+32
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,37 @@ public void Ctor_CreatesFromHostAndPort(string sourceHost, int sourcePort, strin
9292
Assert.Equal(expectedHost, host);
9393
Assert.Equal(expectedPort, port);
9494
}
95+
96+
[Fact]
97+
public void Equals_EmptyHostStringAndDefaultHostString()
98+
{
99+
// Act and Assert
100+
Assert.Equal(new HostString(string.Empty), default(HostString));
101+
Assert.Equal(default(HostString), new HostString(string.Empty));
102+
Assert.True(new HostString(string.Empty) == default(HostString));
103+
Assert.True(default(HostString) == new HostString(string.Empty));
104+
Assert.True(new HostString(string.Empty).Equals(default(HostString)));
105+
Assert.True(default(HostString).Equals(new HostString(string.Empty)));
106+
}
107+
108+
[Fact]
109+
public void NotEquals_DefaultHostStringAndNonNullHostString()
110+
{
111+
// Arrange
112+
var hostString = new HostString("example.com");
113+
114+
// Act and Assert
115+
Assert.NotEqual(hostString, default(HostString));
116+
}
117+
118+
[Fact]
119+
public void NotEquals_EmptyHostStringAndNonNullHostString()
120+
{
121+
// Arrange
122+
var hostString = new HostString("example.com");
123+
124+
// Act and Assert
125+
Assert.NotEqual(hostString, new HostString(string.Empty));
126+
}
95127
}
96128
}

Diff for: test/Microsoft.AspNetCore.Http.Abstractions.Tests/QueryStringTests.cs

+32
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,37 @@ public void AddNameValue_Success(string query1, string name2, string value2, str
105105
var q2 = q1.Add(name2, value2);
106106
Assert.Equal(expected, q2.Value);
107107
}
108+
109+
[Fact]
110+
public void Equals_EmptyQueryStringAndDefaultQueryString()
111+
{
112+
// Act and Assert
113+
Assert.Equal(QueryString.Empty, default(QueryString));
114+
Assert.Equal(default(QueryString), QueryString.Empty);
115+
Assert.True(QueryString.Empty == default(QueryString));
116+
Assert.True(default(QueryString) == QueryString.Empty);
117+
Assert.True(QueryString.Empty.Equals(default(QueryString)));
118+
Assert.True(default(QueryString).Equals(QueryString.Empty));
119+
}
120+
121+
[Fact]
122+
public void NotEquals_DefaultQueryStringAndNonNullQueryString()
123+
{
124+
// Arrange
125+
var queryString = new QueryString("?foo=1");
126+
127+
// Act and Assert
128+
Assert.NotEqual(queryString, default(QueryString));
129+
}
130+
131+
[Fact]
132+
public void NotEquals_EmptyQueryStringAndNonNullQueryString()
133+
{
134+
// Arrange
135+
var queryString = new QueryString("?foo=1");
136+
137+
// Act and Assert
138+
Assert.NotEqual(queryString, QueryString.Empty);
139+
}
108140
}
109141
}

Diff for: test/Microsoft.AspNetCore.Http.Extensions.Tests/UriHelperTests.cs

+29
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,34 @@ public void GetDisplayUrlFromRequest()
6666

6767
Assert.Equal("http://my.hoψst:80/un?escaped/base/un?escaped?name=val%23ue", request.GetDisplayUrl());
6868
}
69+
70+
[Theory]
71+
[InlineData("http://example.com", "http", "example.com", "", "", "")]
72+
[InlineData("https://example.com", "https", "example.com", "", "", "")]
73+
[InlineData("http://example.com/foo/bar", "http", "example.com", "/foo/bar", "", "")]
74+
[InlineData("http://example.com/foo/bar?baz=1", "http", "example.com", "/foo/bar", "?baz=1", "")]
75+
[InlineData("http://example.com/foo#col=2", "http", "example.com", "/foo", "", "#col=2")]
76+
[InlineData("http://example.com/foo?bar=1#col=2", "http", "example.com", "/foo", "?bar=1", "#col=2")]
77+
public void FromAbsoluteUriParsingChecks(
78+
string uri,
79+
string expectedScheme,
80+
string expectedHost,
81+
string expectedPath,
82+
string expectedQuery,
83+
string expectedFragment)
84+
{
85+
string scheme = null;
86+
var host = new HostString();
87+
var path = new PathString();
88+
var query = new QueryString();
89+
var fragment = new FragmentString();
90+
UriHelper.FromAbsolute(uri, out scheme, out host, out path, out query, out fragment);
91+
92+
Assert.Equal(scheme, expectedScheme);
93+
Assert.Equal(host, new HostString(expectedHost));
94+
Assert.Equal(path, new PathString(expectedPath));
95+
Assert.Equal(query, new QueryString(expectedQuery));
96+
Assert.Equal(fragment, new FragmentString(expectedFragment));
97+
}
6998
}
7099
}

0 commit comments

Comments
 (0)