forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpRequestHeaderParser.cs
More file actions
141 lines (121 loc) · 5.49 KB
/
HttpRequestHeaderParser.cs
File metadata and controls
141 lines (121 loc) · 5.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Web.Http;
namespace System.Net.Http.Formatting.Parsers
{
/// <summary>
/// The <see cref="HttpRequestHeaderParser"/> combines <see cref="HttpRequestLineParser"/> for parsing the HTTP Request Line
/// and <see cref="InternetMessageFormatHeaderParser"/> for parsing each header field.
/// </summary>
internal class HttpRequestHeaderParser
{
internal const int DefaultMaxRequestLineSize = 2 * 1024;
internal const int DefaultMaxHeaderSize = 16 * 1024; // Same default size as IIS has for regular requests
private HttpUnsortedRequest _httpRequest;
private HttpRequestState _requestStatus = HttpRequestState.RequestLine;
private HttpRequestLineParser _requestLineParser;
private InternetMessageFormatHeaderParser _headerParser;
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestHeaderParser"/> class.
/// </summary>
/// <param name="httpRequest">The parsed HTTP request without any header sorting.</param>
public HttpRequestHeaderParser(HttpUnsortedRequest httpRequest)
: this(httpRequest, DefaultMaxRequestLineSize, DefaultMaxHeaderSize)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpRequestHeaderParser"/> class.
/// </summary>
/// <param name="httpRequest">The parsed HTTP request without any header sorting.</param>
/// <param name="maxRequestLineSize">The max length of the HTTP request line.</param>
/// <param name="maxHeaderSize">The max length of the HTTP header.</param>
public HttpRequestHeaderParser(HttpUnsortedRequest httpRequest, int maxRequestLineSize, int maxHeaderSize)
{
if (httpRequest == null)
{
throw Error.ArgumentNull("httpRequest");
}
_httpRequest = httpRequest;
// Create request line parser
_requestLineParser = new HttpRequestLineParser(_httpRequest, maxRequestLineSize);
// Create header parser
_headerParser = new InternetMessageFormatHeaderParser(_httpRequest.HttpHeaders, maxHeaderSize);
}
private enum HttpRequestState
{
RequestLine = 0, // parsing request line
RequestHeaders // reading headers
}
/// <summary>
/// Parse an HTTP request header and fill in the <see cref="HttpRequestMessage"/> instance.
/// </summary>
/// <param name="buffer">Request buffer from where request is read</param>
/// <param name="bytesReady">Size of request buffer</param>
/// <param name="bytesConsumed">Offset into request buffer</param>
/// <returns>State of the parser.</returns>
[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Exception is propagated.")]
public ParserState ParseBuffer(
byte[] buffer,
int bytesReady,
ref int bytesConsumed)
{
if (buffer == null)
{
throw Error.ArgumentNull("buffer");
}
ParserState parseStatus = ParserState.NeedMoreData;
ParserState subParseStatus = ParserState.NeedMoreData;
switch (_requestStatus)
{
case HttpRequestState.RequestLine:
try
{
subParseStatus = _requestLineParser.ParseBuffer(buffer, bytesReady, ref bytesConsumed);
}
catch (Exception)
{
subParseStatus = ParserState.Invalid;
}
if (subParseStatus == ParserState.Done)
{
_requestStatus = HttpRequestState.RequestHeaders;
subParseStatus = ParserState.NeedMoreData;
goto case HttpRequestState.RequestHeaders;
}
else if (subParseStatus != ParserState.NeedMoreData)
{
// Report error - either Invalid or DataTooBig
parseStatus = subParseStatus;
break;
}
break; // read more data
case HttpRequestState.RequestHeaders:
if (bytesConsumed >= bytesReady)
{
// we already can tell we need more data
break;
}
try
{
subParseStatus = _headerParser.ParseBuffer(buffer, bytesReady, ref bytesConsumed);
}
catch (Exception)
{
subParseStatus = ParserState.Invalid;
}
if (subParseStatus == ParserState.Done)
{
parseStatus = subParseStatus;
}
else if (subParseStatus != ParserState.NeedMoreData)
{
parseStatus = subParseStatus;
break;
}
break; // need more data
}
return parseStatus;
}
}
}