Skip to content

Commit 27af755

Browse files
committed
#159 remove special encoding
1 parent 8f184f0 commit 27af755

5 files changed

Lines changed: 72 additions & 23 deletions

File tree

src/Directory.Build.props

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
</PropertyGroup>
3939

4040
<ItemGroup>
41+
<PackageReference Include="AssemblyMetadata.Generators" Version="2.0.0" PrivateAssets="All" />
4142
<PackageReference Include="MinVer" Version="5.0.0" PrivateAssets="All" />
4243
</ItemGroup>
4344

@@ -53,5 +54,5 @@
5354
<Visible>false</Visible>
5455
</None>
5556
</ItemGroup>
56-
57+
5758
</Project>

src/FluentRest/FluentDispatcher.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private static async Task<HttpRequestMessage> PrepareRequest(HttpRequestMessage
5252
if (requestMessage.Headers.UserAgent.Count == 0)
5353
{
5454
// user-agent header required
55-
var headerValue = new ProductInfoHeaderValue("FluentRest", "5.0.0.0");
55+
var headerValue = new ProductInfoHeaderValue("FluentRest", ThisAssembly.FileVersion);
5656
requestMessage.Headers.UserAgent.Add(headerValue);
5757
}
5858

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
using System.Text;
2+
3+
namespace FluentRest;
4+
5+
/// <summary>Provide a cached reusable instance of StringBuilder per thread.</summary>
6+
internal static class StringBuilderCache
7+
{
8+
// The value 360 was chosen in discussion with performance experts as a compromise between using
9+
// as little memory per thread as possible and still covering a large part of short-lived
10+
// StringBuilder creations on the startup path of VS designers.
11+
internal const int MaxBuilderSize = 360;
12+
private const int DefaultCapacity = 16; // == StringBuilder.DefaultCapacity
13+
14+
[ThreadStatic]
15+
private static StringBuilder t_cachedInstance;
16+
17+
/// <summary>Get a StringBuilder for the specified capacity.</summary>
18+
/// <remarks>If a StringBuilder of an appropriate size is cached, it will be returned and the cache emptied.</remarks>
19+
public static StringBuilder Acquire(int capacity = DefaultCapacity)
20+
{
21+
if (capacity > MaxBuilderSize)
22+
return new StringBuilder(capacity);
23+
24+
var sb = t_cachedInstance;
25+
if (sb == null)
26+
return new StringBuilder(capacity);
27+
28+
// Avoid StringBuilder block fragmentation by getting a new StringBuilder
29+
// when the requested size is larger than the current capacity
30+
if (capacity > sb.Capacity)
31+
return new StringBuilder(capacity);
32+
33+
t_cachedInstance = null;
34+
sb.Clear();
35+
36+
return sb;
37+
38+
}
39+
40+
/// <summary>Place the specified builder in the cache if it is not too big.</summary>
41+
public static void Release(StringBuilder sb)
42+
{
43+
if (sb.Capacity <= MaxBuilderSize)
44+
t_cachedInstance = sb;
45+
}
46+
47+
/// <summary>Release StringBuilder to the cache, and return the resulting string.</summary>
48+
public static string ToString(StringBuilder sb)
49+
{
50+
string result = sb.ToString();
51+
Release(sb);
52+
return result;
53+
}
54+
}

src/FluentRest/UrlBuilder.cs

Lines changed: 12 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,7 @@ public Uri ToUri()
544544
/// </returns>
545545
public override string ToString()
546546
{
547-
var builder = new StringBuilder();
547+
var builder = StringBuilderCache.Acquire(150);
548548

549549
if (!string.IsNullOrWhiteSpace(_scheme))
550550
builder.Append(_scheme).Append(_schemeDelimiter);
@@ -553,16 +553,16 @@ public override string ToString()
553553
{
554554
builder.Append(_username);
555555
if (!string.IsNullOrWhiteSpace(_password))
556-
builder.Append(":").Append(_password);
556+
builder.Append(':').Append(_password);
557557

558-
builder.Append("@");
558+
builder.Append('@');
559559
}
560560

561561
if (!string.IsNullOrWhiteSpace(_host))
562562
{
563563
builder.Append(_host);
564564
if (_port.HasValue && !IsStandardPort())
565-
builder.Append(":").Append(_port);
565+
builder.Append(':').Append(_port);
566566
}
567567

568568
WritePath(builder);
@@ -571,7 +571,7 @@ public override string ToString()
571571
if (!string.IsNullOrWhiteSpace(_fragment))
572572
builder.Append(_fragment);
573573

574-
return builder.ToString();
574+
return StringBuilderCache.ToString(builder);
575575
}
576576

577577

@@ -586,20 +586,19 @@ private bool IsStandardPort()
586586

587587
private void WritePath(StringBuilder builder)
588588
{
589-
builder.Append("/");
589+
builder.Append('/');
590590
if (Path == null || Path.Count == 0)
591591
return;
592592

593593
int start = builder.Length;
594594
foreach (var p in Path)
595595
{
596596
if (builder.Length > start)
597-
builder.Append("/");
597+
builder.Append('/');
598598

599-
var s = p.Replace(" ", "+");
600-
s = Uri.EscapeUriString(s);
599+
var v = Uri.EscapeDataString(p);
601600

602-
builder.Append(s);
601+
builder.Append(v);
603602
}
604603
}
605604

@@ -608,29 +607,27 @@ private void WriteQueryString(StringBuilder builder)
608607
if (Query == null || Query.Count == 0)
609608
return;
610609

611-
builder.Append("?");
610+
builder.Append('?');
612611

613612
int start = builder.Length;
614613
foreach (var pair in Query)
615614
{
616615
var key = pair.Key;
617616
key = Uri.EscapeDataString(key);
618-
key = key.Replace("%20", "+");
619617

620618
var values = pair.Value.ToList();
621619

622620
foreach (var value in values)
623621
{
624622
if (builder.Length > start)
625-
builder.Append("&");
623+
builder.Append('&');
626624

627625
var v = value;
628626
v = Uri.EscapeDataString(v);
629-
v = v.Replace("%20", "+");
630627

631628
builder
632629
.Append(key)
633-
.Append("=")
630+
.Append('=')
634631
.Append(v);
635632
}
636633
}
@@ -763,6 +760,3 @@ private void ParsePath(string s)
763760
}
764761

765762
}
766-
767-
768-

test/FluentRest.Tests/UrlBuilderTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,10 @@ public UrlBuilderTests(ITestOutputHelper output)
2121

2222
[Theory]
2323
[InlineData("http://foo/bar/baz", "date", "today", "http://foo/bar/baz?date=today")]
24-
[InlineData("http://foo/bar/baz", "date", "sunday afternoon", "http://foo/bar/baz?date=sunday+afternoon")]
24+
[InlineData("http://foo/bar/baz", "date", "sunday afternoon", "http://foo/bar/baz?date=sunday%20afternoon")]
2525
[InlineData("http://foo/bar/baz?date=today", "key1", "value1", "http://foo/bar/baz?date=today&key1=value1")]
26-
[InlineData("http://foo/bar/baz?date=today", "key1", "value 1&", "http://foo/bar/baz?date=today&key1=value+1%26")]
27-
[InlineData("foo/bar/baz?date=today", "key1", "value 1&", "http://foo/bar/baz?date=today&key1=value+1%26")]
26+
[InlineData("http://foo/bar/baz?date=today", "key1", "value 1&", "http://foo/bar/baz?date=today&key1=value%201%26")]
27+
[InlineData("foo/bar/baz?date=today", "key1", "value 1&", "http://foo/bar/baz?date=today&key1=value%201%26")]
2828
public void AppendQuery(string url, string key, string value, string expected)
2929
{
3030
var builder = new UrlBuilder(url);

0 commit comments

Comments
 (0)