Skip to content

Commit 6892f4a

Browse files
committed
Remove gotos
1 parent d3b1b03 commit 6892f4a

File tree

1 file changed

+18
-61
lines changed

1 file changed

+18
-61
lines changed

src/Servers/Kestrel/Core/src/Internal/Http/HttpParser.cs

Lines changed: 18 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -238,12 +238,7 @@ public bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reade
238238
// If not found length with be -1; casting to uint will turn it to uint.MaxValue
239239
// which will be larger than any possible span.Length. This also serves to eliminate
240240
// the bounds check for the next lookup of span[length]
241-
if ((uint)length >= (uint)span.Length)
242-
{
243-
// Not enough data yet.
244-
goto Continue;
245-
}
246-
else
241+
if ((uint)length < (uint)span.Length)
247242
{
248243
// Early memory read to hide latency
249244
var expectedCR = span[length];
@@ -253,7 +248,7 @@ public bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reade
253248
if (expectedCR != ByteCR)
254249
{
255250
// Sequence needs to be CRLF not LF first.
256-
goto Reject;
251+
RejectRequestHeader(span[..length]);
257252
}
258253

259254
if ((uint)length < (uint)span.Length)
@@ -263,48 +258,27 @@ public bool ParseHeaders(TRequestHandler handler, ref SequenceReader<byte> reade
263258
// Correctly has a LF, move to next
264259
length++;
265260

266-
if (expectedLF != ByteLF)
261+
if (expectedLF != ByteLF ||
262+
length < 5 ||
263+
// Exclude the CRLF from the headerLine and parse the header name:value pair
264+
!TryTakeSingleHeader(handler, span[..(length - 2)]))
267265
{
268266
// Sequence needs to be CRLF and not contain an inner CR not part of terminator.
269-
goto Reject;
270-
}
271-
272-
if (length < 5)
273-
{
274267
// Less than min possible headerSpan of 5 bytes a:b\r\n
275-
goto Reject;
276-
}
277-
278-
// Exclude the CRLF from the headerLine and parse the header name:value pair
279-
if (!TryTakeSingleHeader(handler, span[..(length - 2)]))
280-
{
281268
// Not parsable as a valid name:value header pair.
282-
goto Reject;
269+
RejectRequestHeader(span[..length]);
283270
}
284271

285272
// Read the header successfully, skip the reader forward past the headerSpan.
286273
span = span.Slice(length);
287274
reader.Advance(length);
288-
289-
goto Success;
290275
}
291276
else
292277
{
293-
// Not enough data yet.
294-
goto Continue;
278+
// No enough data, set length to 0.
279+
length = 0;
295280
}
296-
297281
}
298-
299-
// Reject and Continue are conditional jump forwards as we expect most headers to be processed first time,
300-
// so we want them to be unpredicted by an unprimied branch predictor.
301-
Reject:
302-
RejectRequestHeader(span[..length]);
303-
Continue:
304-
// Not enough data, reset consumed length to 0
305-
length = 0;
306-
Success:
307-
;
308282
}
309283

310284
// End found in current span
@@ -349,7 +323,6 @@ private int ParseMultiSpanHeader(TRequestHandler handler, ref SequenceReader<byt
349323

350324
SequencePosition lineEnd;
351325
ReadOnlySpan<byte> headerSpan;
352-
int length;
353326
if (currentSlice.Slice(reader.Position, lineEndPosition.Value).Length == currentSlice.Length - 1)
354327
{
355328
// No enough data, so CRLF can't currently be there.
@@ -358,10 +331,9 @@ private int ParseMultiSpanHeader(TRequestHandler handler, ref SequenceReader<byt
358331
// Advance 1 to include CR/LF in lineEnd
359332
lineEnd = currentSlice.GetPosition(1, lineEndPosition.Value);
360333
headerSpan = currentSlice.Slice(reader.Position, lineEnd).ToSpan();
361-
length = headerSpan.Length;
362334
if (headerSpan[^1] != ByteCR)
363335
{
364-
goto Reject;
336+
RejectRequestHeader(headerSpan);
365337
}
366338
return -1;
367339
}
@@ -370,42 +342,27 @@ private int ParseMultiSpanHeader(TRequestHandler handler, ref SequenceReader<byt
370342
lineEnd = currentSlice.GetPosition(2, lineEndPosition.Value);
371343
headerSpan = currentSlice.Slice(reader.Position, lineEnd).ToSpan();
372344

373-
length = headerSpan.Length;
374-
if (length < 5)
345+
if (headerSpan.Length < 5)
375346
{
376347
// Less than min possible headerSpan is 5 bytes a:b\r\n
377-
goto Reject;
348+
RejectRequestHeader(headerSpan);
378349
}
379350

380-
// Sequence needs to be CRLF not LF first.
381351
if (headerSpan[^2] != ByteCR)
382352
{
383-
goto RejectEarly;
353+
// Sequence needs to be CRLF not LF first.
354+
RejectRequestHeader(headerSpan[..^1]);
384355
}
385356

386-
if (headerSpan[^1] != ByteLF)
357+
if (headerSpan[^1] != ByteLF ||
358+
// Exclude the CRLF from the headerLine and parse the header name:value pair
359+
!TryTakeSingleHeader(handler, headerSpan[..^2]))
387360
{
388361
// Sequence needs to be CRLF and not contain an inner CR not part of terminator.
389-
goto Reject;
390-
}
391-
392-
// Exclude the CRLF from the headerLine and parse the header name:value pair
393-
if (!TryTakeSingleHeader(handler, headerSpan[..^2]))
394-
{
395362
// Not parsable as a valid name:value header pair.
396-
goto Reject;
363+
RejectRequestHeader(headerSpan);
397364
}
398365

399-
goto Success;
400-
401-
// Reject is a conditional jump forwards as we expect most headers to be processed first time,
402-
// so we want them to be unpredicted by an unprimied branch predictor.
403-
RejectEarly:
404-
length--;
405-
Reject:
406-
RejectRequestHeader(headerSpan[..length]);
407-
408-
Success:
409366
return headerSpan.Length;
410367
}
411368

0 commit comments

Comments
 (0)