Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 668f574

Browse files
committedSep 2, 2016
Don't allocate for ResponseCookiesFeature
1 parent 30a4b09 commit 668f574

File tree

8 files changed

+144
-151
lines changed

8 files changed

+144
-151
lines changed
 

Diff for: ‎samples/SampleApp/PooledHttpContextFactory.cs

-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Text;
76
using Microsoft.AspNetCore.Http;
87
using Microsoft.AspNetCore.Http.Features;
98
using Microsoft.Extensions.ObjectPool;
@@ -12,7 +11,6 @@ namespace SampleApp
1211
{
1312
public class PooledHttpContextFactory : IHttpContextFactory
1413
{
15-
private readonly ObjectPool<StringBuilder> _builderPool;
1614
private readonly IHttpContextAccessor _httpContextAccessor;
1715
private readonly Stack<PooledHttpContext> _pool = new Stack<PooledHttpContext>();
1816

@@ -28,7 +26,6 @@ public PooledHttpContextFactory(ObjectPoolProvider poolProvider, IHttpContextAcc
2826
throw new ArgumentNullException(nameof(poolProvider));
2927
}
3028

31-
_builderPool = poolProvider.CreateStringBuilderPool();
3229
_httpContextAccessor = httpContextAccessor;
3330
}
3431

@@ -39,9 +36,6 @@ public HttpContext Create(IFeatureCollection featureCollection)
3936
throw new ArgumentNullException(nameof(featureCollection));
4037
}
4138

42-
var responseCookiesFeature = new ResponseCookiesFeature(featureCollection, _builderPool);
43-
featureCollection.Set<IResponseCookiesFeature>(responseCookiesFeature);
44-
4539
PooledHttpContext httpContext = null;
4640
lock (_pool)
4741
{

Diff for: ‎src/Microsoft.AspNetCore.Http/Features/ResponseCookiesFeature.cs

+1-18
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,6 @@ namespace Microsoft.AspNetCore.Http.Features
1313
/// </summary>
1414
public class ResponseCookiesFeature : IResponseCookiesFeature
1515
{
16-
// Object pool will be null only in test scenarios e.g. if code news up a DefaultHttpContext.
17-
private readonly ObjectPool<StringBuilder> _builderPool;
18-
1916
private FeatureReferences<IHttpResponseFeature> _features;
2017
private IResponseCookies _cookiesCollection;
2118

@@ -27,27 +24,13 @@ public class ResponseCookiesFeature : IResponseCookiesFeature
2724
/// <see cref="IResponseCookiesFeature"/> and the <see cref="IHttpResponseFeature"/>.
2825
/// </param>
2926
public ResponseCookiesFeature(IFeatureCollection features)
30-
: this(features, builderPool: null)
31-
{
32-
}
33-
34-
/// <summary>
35-
/// Initializes a new <see cref="ResponseCookiesFeature"/> instance.
36-
/// </summary>
37-
/// <param name="features">
38-
/// <see cref="IFeatureCollection"/> containing all defined features, including this
39-
/// <see cref="IResponseCookiesFeature"/> and the <see cref="IHttpResponseFeature"/>.
40-
/// </param>
41-
/// <param name="builderPool">The <see cref="ObjectPool{T}"/>, if available.</param>
42-
public ResponseCookiesFeature(IFeatureCollection features, ObjectPool<StringBuilder> builderPool)
4327
{
4428
if (features == null)
4529
{
4630
throw new ArgumentNullException(nameof(features));
4731
}
4832

4933
_features = new FeatureReferences<IHttpResponseFeature>(features);
50-
_builderPool = builderPool;
5134
}
5235

5336
private IHttpResponseFeature HttpResponseFeature => _features.Fetch(ref _features.Cache, f => null);
@@ -60,7 +43,7 @@ public IResponseCookies Cookies
6043
if (_cookiesCollection == null)
6144
{
6245
var headers = HttpResponseFeature.Headers;
63-
_cookiesCollection = new ResponseCookies(headers, _builderPool);
46+
_cookiesCollection = new ResponseCookies(headers);
6447
}
6548

6649
return _cookiesCollection;

Diff for: ‎src/Microsoft.AspNetCore.Http/HttpContextFactory.cs

-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Text;
65
using Microsoft.AspNetCore.Http.Features;
76
using Microsoft.Extensions.ObjectPool;
87
using Microsoft.Extensions.Options;
@@ -11,7 +10,6 @@ namespace Microsoft.AspNetCore.Http
1110
{
1211
public class HttpContextFactory : IHttpContextFactory
1312
{
14-
private readonly ObjectPool<StringBuilder> _builderPool;
1513
private readonly IHttpContextAccessor _httpContextAccessor;
1614
private readonly FormOptions _formOptions;
1715

@@ -31,7 +29,6 @@ public HttpContextFactory(ObjectPoolProvider poolProvider, IOptions<FormOptions>
3129
throw new ArgumentNullException(nameof(formOptions));
3230
}
3331

34-
_builderPool = poolProvider.CreateStringBuilderPool();
3532
_formOptions = formOptions.Value;
3633
_httpContextAccessor = httpContextAccessor;
3734
}
@@ -43,9 +40,6 @@ public HttpContext Create(IFeatureCollection featureCollection)
4340
throw new ArgumentNullException(nameof(featureCollection));
4441
}
4542

46-
var responseCookiesFeature = new ResponseCookiesFeature(featureCollection, _builderPool);
47-
featureCollection.Set<IResponseCookiesFeature>(responseCookiesFeature);
48-
4943
var httpContext = new DefaultHttpContext(featureCollection);
5044
if (_httpContextAccessor != null)
5145
{

Diff for: ‎src/Microsoft.AspNetCore.Http/Internal/ResponseCookies.cs

+3-43
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33

44
using System;
55
using System.Collections.Generic;
6-
using System.Text;
7-
using Microsoft.Extensions.ObjectPool;
86
using Microsoft.Extensions.Primitives;
97
using Microsoft.Net.Http.Headers;
108

@@ -15,22 +13,18 @@ namespace Microsoft.AspNetCore.Http.Internal
1513
/// </summary>
1614
public class ResponseCookies : IResponseCookies
1715
{
18-
private readonly ObjectPool<StringBuilder> _builderPool;
19-
2016
/// <summary>
2117
/// Create a new wrapper.
2218
/// </summary>
2319
/// <param name="headers">The <see cref="IHeaderDictionary"/> for the response.</param>
24-
/// <param name="builderPool">The <see cref="ObjectPool{T}"/>, if available.</param>
25-
public ResponseCookies(IHeaderDictionary headers, ObjectPool<StringBuilder> builderPool)
20+
public ResponseCookies(IHeaderDictionary headers)
2621
{
2722
if (headers == null)
2823
{
2924
throw new ArgumentNullException(nameof(headers));
3025
}
3126

3227
Headers = headers;
33-
_builderPool = builderPool;
3428
}
3529

3630
private IHeaderDictionary Headers { get; set; }
@@ -45,24 +39,7 @@ public void Append(string key, string value)
4539
Path = "/"
4640
};
4741

48-
string cookieValue;
49-
if (_builderPool == null)
50-
{
51-
cookieValue = setCookieHeaderValue.ToString();
52-
}
53-
else
54-
{
55-
var stringBuilder = _builderPool.Get();
56-
try
57-
{
58-
setCookieHeaderValue.AppendToStringBuilder(stringBuilder);
59-
cookieValue = stringBuilder.ToString();
60-
}
61-
finally
62-
{
63-
_builderPool.Return(stringBuilder);
64-
}
65-
}
42+
var cookieValue = setCookieHeaderValue.ToString();
6643

6744
Headers[HeaderNames.SetCookie] = StringValues.Concat(Headers[HeaderNames.SetCookie], cookieValue);
6845
}
@@ -86,24 +63,7 @@ public void Append(string key, string value, CookieOptions options)
8663
HttpOnly = options.HttpOnly,
8764
};
8865

89-
string cookieValue;
90-
if (_builderPool == null)
91-
{
92-
cookieValue = setCookieHeaderValue.ToString();
93-
}
94-
else
95-
{
96-
var stringBuilder = _builderPool.Get();
97-
try
98-
{
99-
setCookieHeaderValue.AppendToStringBuilder(stringBuilder);
100-
cookieValue = stringBuilder.ToString();
101-
}
102-
finally
103-
{
104-
_builderPool.Return(stringBuilder);
105-
}
106-
}
66+
var cookieValue = setCookieHeaderValue.ToString();
10767

10868
Headers[HeaderNames.SetCookie] = StringValues.Concat(Headers[HeaderNames.SetCookie], cookieValue);
10969
}

Diff for: ‎src/Microsoft.Net.Http.Headers/SetCookieHeaderValue.cs

+122-33
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics.Contracts;
7-
using System.Text;
7+
using System.Runtime.CompilerServices;
88

99
namespace Microsoft.Net.Http.Headers
1010
{
@@ -87,68 +87,157 @@ public string Value
8787
public bool HttpOnly { get; set; }
8888

8989
// name="val ue"; expires=Sun, 06 Nov 1994 08:49:37 GMT; max-age=86400; domain=domain1; path=path1; secure; httponly
90-
public override string ToString()
90+
public override unsafe string ToString()
9191
{
92-
StringBuilder header = new StringBuilder();
93-
AppendToStringBuilder(header);
92+
const string equals = "=";
93+
const string separator = "; ";
9494

95-
return header.ToString();
96-
}
95+
var length = _name.Length + equals.Length + _value.Length;
9796

98-
/// <summary>
99-
/// Append string representation of this <see cref="SetCookieHeaderValue"/> to given
100-
/// <paramref name="builder"/>.
101-
/// </summary>
102-
/// <param name="builder">
103-
/// The <see cref="StringBuilder"/> to receive the string representation of this
104-
/// <see cref="SetCookieHeaderValue"/>.
105-
/// </param>
106-
public void AppendToStringBuilder(StringBuilder builder)
107-
{
108-
builder.Append(_name);
109-
builder.Append("=");
110-
builder.Append(_value);
97+
string expires = null;
98+
string maxAge = null;
11199

112100
if (Expires.HasValue)
113101
{
114-
AppendSegment(builder, ExpiresToken, HeaderUtilities.FormatDate(Expires.Value));
102+
expires = HeaderUtilities.FormatDate(Expires.Value);
103+
length += separator.Length + ExpiresToken.Length + equals.Length + expires.Length;
115104
}
116105

117106
if (MaxAge.HasValue)
118107
{
119-
AppendSegment(builder, MaxAgeToken, HeaderUtilities.FormatInt64((long)MaxAge.Value.TotalSeconds));
108+
maxAge = HeaderUtilities.FormatInt64((long)MaxAge.Value.TotalSeconds);
109+
length += separator.Length + MaxAgeToken.Length + equals.Length + maxAge.Length;
120110
}
121111

122112
if (Domain != null)
123113
{
124-
AppendSegment(builder, DomainToken, Domain);
114+
length += separator.Length + DomainToken.Length + equals.Length + Domain.Length;
125115
}
126116

127117
if (Path != null)
128118
{
129-
AppendSegment(builder, PathToken, Path);
119+
length += separator.Length + PathToken.Length + equals.Length + Path.Length;
130120
}
131121

132122
if (Secure)
133123
{
134-
AppendSegment(builder, SecureToken, null);
124+
length += separator.Length + SecureToken.Length;
135125
}
136126

137127
if (HttpOnly)
138128
{
139-
AppendSegment(builder, HttpOnlyToken, null);
129+
length += separator.Length + HttpOnlyToken.Length;
140130
}
141-
}
142131

143-
private static void AppendSegment(StringBuilder builder, string name, string value)
144-
{
145-
builder.Append("; ");
146-
builder.Append(name);
147-
if (value != null)
132+
var header = new string('\0', length);
133+
134+
fixed (char* pSeparator = separator)
135+
fixed (char* pEquals = equals)
136+
fixed (char* pHeader = header)
148137
{
149-
builder.Append("=");
150-
builder.Append(value);
138+
var cHeader = pHeader;
139+
fixed (char* pName = _name)
140+
{
141+
Unsafe.CopyBlock(cHeader, pName, (uint)_name.Length * 2);
142+
cHeader += _name.Length;
143+
}
144+
145+
Unsafe.CopyBlock(cHeader, pEquals, (uint)equals.Length * 2);
146+
cHeader += equals.Length;
147+
148+
fixed (char* pValue = _value)
149+
{
150+
Unsafe.CopyBlock(cHeader, pValue, (uint)_value.Length * 2);
151+
cHeader += _value.Length;
152+
}
153+
154+
if (expires != null)
155+
{
156+
fixed (char* pExpires = expires)
157+
fixed (char* pExpiresToken = ExpiresToken)
158+
{
159+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
160+
cHeader += separator.Length;
161+
Unsafe.CopyBlock(cHeader, pExpiresToken, (uint)ExpiresToken.Length * 2);
162+
cHeader += ExpiresToken.Length;
163+
Unsafe.CopyBlock(cHeader, pEquals, (uint)equals.Length * 2);
164+
cHeader += equals.Length;
165+
Unsafe.CopyBlock(cHeader, pExpires, (uint)expires.Length * 2);
166+
cHeader += expires.Length;
167+
}
168+
}
169+
170+
if (maxAge != null)
171+
{
172+
fixed (char* pMaxAge = maxAge)
173+
fixed (char* pMaxAgeToken = MaxAgeToken)
174+
{
175+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
176+
cHeader += separator.Length;
177+
Unsafe.CopyBlock(cHeader, pMaxAgeToken, (uint)MaxAgeToken.Length * 2);
178+
cHeader += MaxAgeToken.Length;
179+
Unsafe.CopyBlock(cHeader, pEquals, (uint)equals.Length * 2);
180+
cHeader += equals.Length;
181+
Unsafe.CopyBlock(cHeader, pMaxAge, (uint)maxAge.Length * 2);
182+
cHeader += maxAge.Length;
183+
}
184+
}
185+
186+
if (Domain != null)
187+
{
188+
fixed (char* pDomain = Domain)
189+
fixed (char* pDomainToken = DomainToken)
190+
{
191+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
192+
cHeader += separator.Length;
193+
Unsafe.CopyBlock(cHeader, pDomainToken, (uint)DomainToken.Length * 2);
194+
cHeader += DomainToken.Length;
195+
Unsafe.CopyBlock(cHeader, pEquals, (uint)equals.Length * 2);
196+
cHeader += equals.Length;
197+
Unsafe.CopyBlock(cHeader, pDomain, (uint)Domain.Length * 2);
198+
cHeader += Domain.Length;
199+
}
200+
}
201+
202+
if (Path != null)
203+
{
204+
fixed (char* pPath = Path)
205+
fixed (char* pPathToken = PathToken)
206+
{
207+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
208+
cHeader += separator.Length;
209+
Unsafe.CopyBlock(cHeader, pPathToken, (uint)PathToken.Length * 2);
210+
cHeader += PathToken.Length;
211+
Unsafe.CopyBlock(cHeader, pEquals, (uint)equals.Length * 2);
212+
cHeader += equals.Length;
213+
Unsafe.CopyBlock(cHeader, pPath, (uint)Path.Length * 2);
214+
cHeader += Path.Length;
215+
}
216+
}
217+
218+
if (Secure)
219+
{
220+
fixed (char* pSecureToken = SecureToken)
221+
{
222+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
223+
cHeader += separator.Length;
224+
Unsafe.CopyBlock(cHeader, pSecureToken, (uint)SecureToken.Length * 2);
225+
cHeader += SecureToken.Length;
226+
}
227+
}
228+
229+
if (HttpOnly)
230+
{
231+
fixed (char* pHttpOnlyToken = HttpOnlyToken)
232+
{
233+
Unsafe.CopyBlock(cHeader, pSeparator, (uint)separator.Length * 2);
234+
cHeader += separator.Length;
235+
Unsafe.CopyBlock(cHeader, pHttpOnlyToken, (uint)HttpOnlyToken.Length * 2);
236+
}
237+
}
151238
}
239+
240+
return header;
152241
}
153242

154243
public static SetCookieHeaderValue Parse(string input)

0 commit comments

Comments
 (0)
This repository has been archived.