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

Commit 2f83855

Browse files
Justin KotalikJustin Kotalik
Justin Kotalik
authored and
Justin Kotalik
committed
Addresses #678 and #679
1 parent e320755 commit 2f83855

File tree

8 files changed

+247
-8
lines changed

8 files changed

+247
-8
lines changed

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)

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>

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)

src/Microsoft.AspNetCore.Http.Extensions/UriHelper.cs

+64
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,67 @@ 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+
// Satisfy the out parameters
98+
path = new PathString();
99+
query = new QueryString();
100+
fragment = new FragmentString();
101+
var startIndex = uri.IndexOf(SchemeDelimiter);
102+
103+
if (startIndex < 0)
104+
{
105+
throw new FormatException("No scheme delimiter in uri.");
106+
}
107+
108+
scheme = uri.Substring(0, startIndex);
109+
110+
// PERF: Calculate the end of the scheme for next IndexOf
111+
startIndex += SchemeDelimiter.Length;
112+
113+
var searchIndex = -1;
114+
var limit = uri.Length;
115+
116+
if ((searchIndex = uri.IndexOf(Pound, startIndex)) >= 0 && searchIndex < limit)
117+
{
118+
fragment = FragmentString.FromUriComponent(uri.Substring(searchIndex));
119+
limit = searchIndex;
120+
}
121+
122+
if ((searchIndex = uri.IndexOf(QuestionMark, startIndex)) >= 0 && searchIndex < limit)
123+
{
124+
query = QueryString.FromUriComponent(uri.Substring(searchIndex, limit - searchIndex));
125+
limit = searchIndex;
126+
}
127+
128+
if ((searchIndex = uri.IndexOf(ForwardSlash, startIndex)) >= 0 && searchIndex < limit)
129+
{
130+
path = PathString.FromUriComponent(uri.Substring(searchIndex, limit - searchIndex));
131+
limit = searchIndex;
132+
}
133+
134+
host = HostString.FromUriComponent(uri.Substring(startIndex, limit - startIndex));
135+
}
136+
73137
/// <summary>
74138
/// Generates a string from the given absolute or relative Uri that is appropriately encoded for use in
75139
/// HTTP headers. Note that a unicode host name will be encoded as punycode.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
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+
}
19+
20+
[Fact]
21+
public void NotEquals_DefaultFragmentStringAndNonNullFragmentString()
22+
{
23+
// Arrange
24+
var fragmentString = new FragmentString("#col=1");
25+
26+
// Act and Assert
27+
Assert.NotEqual(fragmentString, default(FragmentString));
28+
}
29+
30+
[Fact]
31+
public void NotEquals_EmptyFragmentStringAndNonNullFragmentString()
32+
{
33+
// Arrange
34+
var fragmentString = new FragmentString("#col=1");
35+
36+
// Act and Assert
37+
Assert.NotEqual(fragmentString, FragmentString.Empty);
38+
}
39+
}
40+
}

test/Microsoft.AspNetCore.Http.Abstractions.Tests/HostStringTest.cs

+30
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,35 @@ 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+
}
105+
106+
[Fact]
107+
public void NotEquals_DefaultHostStringAndNonNullHostString()
108+
{
109+
// Arrange
110+
var hostString = new HostString("example.com");
111+
112+
// Act and Assert
113+
Assert.NotEqual(hostString, default(HostString));
114+
}
115+
116+
[Fact]
117+
public void NotEquals_EmptyHostStringAndNonNullHostString()
118+
{
119+
// Arrange
120+
var hostString = new HostString("example.com");
121+
122+
// Act and Assert
123+
Assert.NotEqual(hostString, new HostString(string.Empty));
124+
}
95125
}
96126
}

test/Microsoft.AspNetCore.Http.Abstractions.Tests/QueryStringTests.cs

+30
Original file line numberDiff line numberDiff line change
@@ -105,5 +105,35 @@ 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+
}
118+
119+
[Fact]
120+
public void NotEquals_DefaultQueryStringAndNonNullQueryString()
121+
{
122+
// Arrange
123+
var queryString = new QueryString("?foo=1");
124+
125+
// Act and Assert
126+
Assert.NotEqual(queryString, default(QueryString));
127+
}
128+
129+
[Fact]
130+
public void NotEquals_EmptyQueryStringAndNonNullQueryString()
131+
{
132+
// Arrange
133+
var queryString = new QueryString("?foo=1");
134+
135+
// Act and Assert
136+
Assert.NotEqual(queryString, QueryString.Empty);
137+
}
108138
}
109139
}

test/Microsoft.AspNetCore.Http.Extensions.Tests/UriHelperTests.cs

+63
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,68 @@ 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+
[InlineData("http://example.com?bar=1#col=2", "http", "example.com", "", "?bar=1", "#col=2")]
78+
[InlineData("http://example.com#frag?stillfrag/stillfrag", "http", "example.com", "", "", "#frag?stillfrag/stillfrag")]
79+
[InlineData("http://example.com?q/stillq#frag?stillfrag/stillfrag", "http", "example.com", "", "?q/stillq", "#frag?stillfrag/stillfrag")]
80+
[InlineData("http://example.com/fo%23o#col=2", "http", "example.com", "/fo#o", "", "#col=2")]
81+
[InlineData("http://example.com/fo%3Fo#col=2", "http", "example.com", "/fo?o", "", "#col=2")]
82+
[InlineData("ftp://example.com/", "ftp", "example.com", "/", "", "")]
83+
[InlineData("https://127.0.0.0:80/bar", "https", "127.0.0.0:80", "/bar", "", "")]
84+
[InlineData("http://[1080:0:0:0:8:800:200C:417A]/index.html", "http", "[1080:0:0:0:8:800:200C:417A]", "/index.html", "", "")]
85+
[InlineData("http://example.com///", "http", "example.com", "///", "", "")]
86+
[InlineData("http://example.com///", "http", "example.com", "///", "", "")]
87+
public void FromAbsoluteUriParsingChecks(
88+
string uri,
89+
string expectedScheme,
90+
string expectedHost,
91+
string expectedPath,
92+
string expectedQuery,
93+
string expectedFragment)
94+
{
95+
string scheme = null;
96+
var host = new HostString();
97+
var path = new PathString();
98+
var query = new QueryString();
99+
var fragment = new FragmentString();
100+
UriHelper.FromAbsolute(uri, out scheme, out host, out path, out query, out fragment);
101+
102+
Assert.Equal(scheme, expectedScheme);
103+
Assert.Equal(host, new HostString(expectedHost));
104+
Assert.Equal(path, new PathString(expectedPath));
105+
Assert.Equal(query, new QueryString(expectedQuery));
106+
Assert.Equal(fragment, new FragmentString(expectedFragment));
107+
}
108+
109+
[Fact]
110+
public void FromAbsoluteToBuildAbsolute()
111+
{
112+
var scheme = "http";
113+
var host = new HostString("example.com");
114+
var path = new PathString("/index.html");
115+
var query = new QueryString("?foo=1");
116+
var fragment = new FragmentString("#col=1");
117+
var request = UriHelper.BuildAbsolute(scheme, host, path:path, query:query, fragment:fragment);
118+
119+
string resScheme = null;
120+
var resHost = new HostString();
121+
var resPath = new PathString();
122+
var resQuery = new QueryString();
123+
var resFragment = new FragmentString();
124+
UriHelper.FromAbsolute(request, out resScheme, out resHost, out resPath, out resQuery, out resFragment);
125+
126+
Assert.Equal(scheme, resScheme);
127+
Assert.Equal(host, resHost);
128+
Assert.Equal(path, resPath);
129+
Assert.Equal(query, resQuery);
130+
Assert.Equal(fragment, resFragment);
131+
}
69132
}
70133
}

0 commit comments

Comments
 (0)