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

Commit 9e8459c

Browse files
committed
Tweak Http1Connection to improve performance
1 parent 8abb6f0 commit 9e8459c

File tree

5 files changed

+74
-51
lines changed

5 files changed

+74
-51
lines changed

benchmarks/Kestrel.Performance/Http1ConnectionParsingOverheadBenchmark.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,14 @@ private void ParseRequest()
7878
{
7979
_http1Connection.Reset();
8080
var reader = new BufferReader<byte>(_buffer);
81+
var length = _buffer.Length;
8182

82-
if (!_http1Connection.TakeStartLine(ref reader))
83+
if (!_http1Connection.TakeStartLine(ref reader, length))
8384
{
8485
ErrorUtilities.ThrowInvalidRequestLine();
8586
}
8687

87-
if (!_http1Connection.TakeMessageHeaders(ref reader))
88+
if (!_http1Connection.TakeMessageHeaders(ref reader, length))
8889
{
8990
ErrorUtilities.ThrowInvalidRequestHeaders();
9091
}
@@ -94,8 +95,9 @@ private void ParseRequestLine()
9495
{
9596
_http1Connection.Reset();
9697
var reader = new BufferReader<byte>(_buffer);
98+
var length = _buffer.Length;
9799

98-
if (!_http1Connection.TakeStartLine(ref reader))
100+
if (!_http1Connection.TakeStartLine(ref reader, length))
99101
{
100102
ErrorUtilities.ThrowInvalidRequestLine();
101103
}
@@ -105,8 +107,9 @@ private void ParseRequestHeaders()
105107
{
106108
_http1Connection.Reset();
107109
var reader = new BufferReader<byte>(_buffer);
110+
var length = _buffer.Length;
108111

109-
if (!_http1Connection.TakeMessageHeaders(ref reader))
112+
if (!_http1Connection.TakeMessageHeaders(ref reader, length))
110113
{
111114
ErrorUtilities.ThrowInvalidRequestHeaders();
112115
}

benchmarks/Kestrel.Performance/RequestParsingBenchmark.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,18 @@ private void ParseDataDrainBuffer()
149149

150150
var readableBuffer = awaitable.GetAwaiter().GetResult().Buffer;
151151
var reader = new BufferReader<byte>(readableBuffer);
152+
var length = readableBuffer.Length;
152153

153154
do
154155
{
155156
Http1Connection.Reset();
156157

157-
if (!Http1Connection.TakeStartLine(ref reader))
158+
if (!Http1Connection.TakeStartLine(ref reader, length))
158159
{
159160
ErrorUtilities.ThrowInvalidRequestLine();
160161
}
161162

162-
if (!Http1Connection.TakeMessageHeaders(ref reader))
163+
if (!Http1Connection.TakeMessageHeaders(ref reader, length))
163164
{
164165
ErrorUtilities.ThrowInvalidRequestHeaders();
165166
}
@@ -182,11 +183,12 @@ private void ParseData()
182183

183184
var result = awaitable.GetAwaiter().GetResult();
184185
var readableBuffer = result.Buffer;
186+
var length = readableBuffer.Length;
185187
var reader = new BufferReader<byte>(readableBuffer);
186188

187189
Http1Connection.Reset();
188190

189-
if (!Http1Connection.TakeStartLine(ref reader))
191+
if (!Http1Connection.TakeStartLine(ref reader, length))
190192
{
191193
ErrorUtilities.ThrowInvalidRequestLine();
192194
}
@@ -196,7 +198,7 @@ private void ParseData()
196198
readableBuffer = result.Buffer;
197199
reader = new BufferReader<byte>(readableBuffer);
198200

199-
if (!Http1Connection.TakeMessageHeaders(ref reader))
201+
if (!Http1Connection.TakeMessageHeaders(ref reader, length))
200202
{
201203
ErrorUtilities.ThrowInvalidRequestHeaders();
202204
}

src/Kestrel.Core/Internal/Http/Http1Connection.cs

Lines changed: 56 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition con
140140
examined = buffer.End;
141141

142142
var reader = new BufferReader<byte>(buffer);
143+
var length = buffer.Length;
143144

144145
switch (_requestProcessingStatus)
145146
{
@@ -154,18 +155,18 @@ public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition con
154155
_requestProcessingStatus = RequestProcessingStatus.ParsingRequestLine;
155156
goto case RequestProcessingStatus.ParsingRequestLine;
156157
case RequestProcessingStatus.ParsingRequestLine:
157-
if (TakeStartLine(ref reader))
158+
if (TakeStartLine(ref reader, length))
158159
{
159160
_requestProcessingStatus = RequestProcessingStatus.ParsingHeaders;
160161
goto case RequestProcessingStatus.ParsingHeaders;
161162
}
162163
else
163164
{
164165
consumed = reader.Position;
165-
break;
166166
}
167+
break;
167168
case RequestProcessingStatus.ParsingHeaders:
168-
if (TakeMessageHeaders(ref reader))
169+
if (TakeMessageHeaders(ref reader, length))
169170
{
170171
_requestProcessingStatus = RequestProcessingStatus.AppStarted;
171172
examined = reader.Position;
@@ -175,72 +176,87 @@ public void ParseRequest(ReadOnlySequence<byte> buffer, out SequencePosition con
175176
{
176177
consumed = reader.Position;
177178
}
178-
179179
break;
180180
}
181+
182+
//Done:;
181183
}
182184

183-
public bool TakeStartLine(ref BufferReader<byte> reader)
185+
public bool TakeStartLine(ref BufferReader<byte> reader, long length)
184186
{
185-
var overLength = false;
186-
var sequence = reader.Sequence;
187-
if (sequence.Length >= ServerOptions.Limits.MaxRequestLineSize)
187+
bool result;
188+
if (length >= ServerOptions.Limits.MaxRequestLineSize)
188189
{
189-
// More data in the reader than we want to allow, cap it
190-
reader = new BufferReader<byte>(sequence.Slice(sequence.Start, ServerOptions.Limits.MaxRequestLineSize));
191-
overLength = true;
190+
result = TakeOverlengthStartLine(ref reader);
192191
}
192+
else
193+
{
194+
result = _parser.ParseRequestLine(new Http1ParsingHandler(this), ref reader);
195+
}
196+
197+
return result;
198+
}
199+
200+
private bool TakeOverlengthStartLine(ref BufferReader<byte> reader)
201+
{
202+
// More data in the reader than we want to allow, cap it
203+
var sequence = reader.Sequence;
204+
reader = new BufferReader<byte>(sequence.Slice(sequence.Start, ServerOptions.Limits.MaxRequestLineSize));
193205

194206
var result = _parser.ParseRequestLine(new Http1ParsingHandler(this), ref reader);
195207

196-
if (overLength)
208+
if (result)
197209
{
198-
if (result)
199-
{
200-
// Need to reset the reader to the right end point
201-
var consumed = reader.Consumed;
202-
reader = new BufferReader<byte>(sequence);
203-
reader.Advance(consumed);
204-
}
205-
else
206-
{
207-
BadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
208-
}
210+
// Need to reset the reader to the right end point
211+
var consumed = reader.Consumed;
212+
reader = new BufferReader<byte>(sequence);
213+
reader.Advance(consumed);
214+
}
215+
else
216+
{
217+
BadHttpRequestException.Throw(RequestRejectionReason.RequestLineTooLong);
209218
}
210219

211220
return result;
212221
}
213222

214-
public bool TakeMessageHeaders(ref BufferReader<byte> reader)
223+
public bool TakeMessageHeaders(ref BufferReader<byte> reader, long length)
215224
{
216-
// Make sure the buffer is limited
217-
var overLength = false;
218-
var sequence = reader.Sequence;
219225
var consumed = reader.Consumed;
220-
var remaining = sequence.Length - consumed;
226+
var remaining = length - consumed;
227+
bool result;
221228

222229
if (remaining >= _remainingRequestHeadersBytesAllowed)
223230
{
224-
// More data in the reader than we want to allow, cap it
225-
reader = new BufferReader<byte>(sequence.Slice(reader.Position, _remainingRequestHeadersBytesAllowed));
226-
consumed = 0;
231+
// Possibly over max size, go down slow path
232+
result = TakeOverlengthMessageHeaders(ref reader);
233+
}
234+
else
235+
{
236+
result = _parser.ParseHeaders(new Http1ParsingHandler(this), ref reader);
237+
_remainingRequestHeadersBytesAllowed -= (int)(reader.Consumed - consumed);
238+
}
227239

228-
// If we sliced it means the current buffer bigger than what we're
229-
// allowed to look at
230-
overLength = true;
240+
if (result)
241+
{
242+
TimeoutControl.CancelTimeout();
231243
}
232244

245+
return result;
246+
}
247+
248+
private bool TakeOverlengthMessageHeaders(ref BufferReader<byte> reader)
249+
{
250+
// More data in the reader than we want to allow, cap it
251+
reader = new BufferReader<byte>(reader.Sequence.Slice(reader.Position, _remainingRequestHeadersBytesAllowed));
252+
233253
var result = _parser.ParseHeaders(new Http1ParsingHandler(this), ref reader);
234-
_remainingRequestHeadersBytesAllowed -= (int)(reader.Consumed - consumed);
254+
_remainingRequestHeadersBytesAllowed -= (int)reader.Consumed;
235255

236-
if (!result && overLength)
256+
if (!result)
237257
{
238258
BadHttpRequestException.Throw(RequestRejectionReason.HeadersExceedMaxTotalSize);
239259
}
240-
if (result)
241-
{
242-
TimeoutControl.CancelTimeout();
243-
}
244260

245261
return result;
246262
}

src/Kestrel.Core/Internal/Http/Http1MessageBody.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,7 @@ protected override bool Read(ReadOnlySequence<byte> readableBuffer, PipeWriter w
447447
if (_mode == Mode.TrailerHeaders)
448448
{
449449
BufferReader<byte> reader = new BufferReader<byte>(readableBuffer);
450-
if (_context.TakeMessageHeaders(ref reader))
450+
if (_context.TakeMessageHeaders(ref reader, readableBuffer.Length))
451451
{
452452
_mode = Mode.Complete;
453453
consumed = reader.Position;

test/Kestrel.Core.Tests/Http1ConnectionTests.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private static bool TakeMessageHeaders(
106106
out SequencePosition examined)
107107
{
108108
var reader = new BufferReader<byte>(sequence);
109-
if (connection.TakeMessageHeaders(ref reader))
109+
if (connection.TakeMessageHeaders(ref reader, sequence.Length))
110110
{
111111
examined = reader.Position;
112112
consumed = reader.Position;
@@ -127,7 +127,9 @@ private static bool TakeStartLine(
127127
out SequencePosition examined)
128128
{
129129
var reader = new BufferReader<byte>(sequence);
130-
if (connection.TakeStartLine(ref reader))
130+
var length = sequence.Length;
131+
132+
if (connection.TakeStartLine(ref reader, length))
131133
{
132134
examined = reader.Position;
133135
consumed = reader.Position;

0 commit comments

Comments
 (0)