forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathHttpResponseHeaderParser.cs
More file actions
141 lines (121 loc) · 5.52 KB
/
Copy pathHttpResponseHeaderParser.cs
File metadata and controls
141 lines (121 loc) · 5.52 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="HttpResponseHeaderParser"/> combines <see cref="HttpStatusLineParser"/> for parsing the HTTP Status Line
/// and <see cref="InternetMessageFormatHeaderParser"/> for parsing each header field.
/// </summary>
internal class HttpResponseHeaderParser
{
internal const int DefaultMaxStatusLineSize = 2 * 1024;
internal const int DefaultMaxHeaderSize = 16 * 1024; // Same default size as IIS has for HTTP requests
private HttpUnsortedResponse _httpResponse;
private HttpResponseState _responseStatus = HttpResponseState.StatusLine;
private HttpStatusLineParser _statusLineParser;
private InternetMessageFormatHeaderParser _headerParser;
/// <summary>
/// Initializes a new instance of the <see cref="HttpResponseHeaderParser"/> class.
/// </summary>
/// <param name="httpResponse">The parsed HTTP response without any header sorting.</param>
public HttpResponseHeaderParser(HttpUnsortedResponse httpResponse)
: this(httpResponse, DefaultMaxStatusLineSize, DefaultMaxHeaderSize)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HttpResponseHeaderParser"/> class.
/// </summary>
/// <param name="httpResponse">The parsed HTTP response without any header sorting.</param>
/// <param name="maxResponseLineSize">The max length of the HTTP status line.</param>
/// <param name="maxHeaderSize">The max length of the HTTP header.</param>
public HttpResponseHeaderParser(HttpUnsortedResponse httpResponse, int maxResponseLineSize, int maxHeaderSize)
{
if (httpResponse == null)
{
throw Error.ArgumentNull("httpResponse");
}
_httpResponse = httpResponse;
// Create status line parser
_statusLineParser = new HttpStatusLineParser(_httpResponse, maxResponseLineSize);
// Create header parser
_headerParser = new InternetMessageFormatHeaderParser(_httpResponse.HttpHeaders, maxHeaderSize);
}
private enum HttpResponseState
{
StatusLine = 0, // parsing status line
ResponseHeaders // reading headers
}
/// <summary>
/// Parse an HTTP response header and fill in the <see cref="HttpResponseMessage"/> instance.
/// </summary>
/// <param name="buffer">Response buffer from where response is read</param>
/// <param name="bytesReady">Size of response buffer</param>
/// <param name="bytesConsumed">Offset into response 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 (_responseStatus)
{
case HttpResponseState.StatusLine:
try
{
subParseStatus = _statusLineParser.ParseBuffer(buffer, bytesReady, ref bytesConsumed);
}
catch (Exception)
{
subParseStatus = ParserState.Invalid;
}
if (subParseStatus == ParserState.Done)
{
_responseStatus = HttpResponseState.ResponseHeaders;
subParseStatus = ParserState.NeedMoreData;
goto case HttpResponseState.ResponseHeaders;
}
else if (subParseStatus != ParserState.NeedMoreData)
{
// Report error - either Invalid or DataTooBig
parseStatus = subParseStatus;
break;
}
break; // read more data
case HttpResponseState.ResponseHeaders:
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;
}
}
}