public void ResponseHeaderParserAcceptsCustomStatusCodes(HttpStatusCode status) { byte[] data = CreateBuffer( "HTTP/1.1", ((int)status).ToString(), "Reason", ParserData.ValidHeaders ); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse result = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(result); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult( result, new Version("1.1"), status, "Reason", ParserData.ValidHeaders ); } }
public void ResponseHeaderParserAcceptsValidVersion(Version version) { byte[] data = CreateBuffer( String.Format("HTTP/{0}", version.ToString(2)), "200", "Reason", ParserData.ValidHeaders ); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse result = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(result); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult( result, version, HttpStatusCode.OK, "Reason", ParserData.ValidHeaders ); } }
public void HttpStatusLineParserConstructorTest() { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); Assert.NotNull(statusLine); Assert.ThrowsArgumentGreaterThanOrEqualTo( () => new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize - 1), "maxStatusLineSize", ParserData.MinStatusLineSize.ToString(), ParserData.MinStatusLineSize - 1 ); HttpStatusLineParser parser = new HttpStatusLineParser( statusLine, ParserData.MinStatusLineSize ); Assert.NotNull(parser); Assert.ThrowsArgumentNull( () => { new HttpStatusLineParser(null, ParserData.MinStatusLineSize); }, "httpResponse" ); }
private static void ValidateResult( HttpUnsortedResponse statusLine, Version version, HttpStatusCode statusCode, string reasonPhrase, Dictionary <string, string> headers ) { Assert.Equal(version, statusLine.Version); Assert.Equal(statusCode, statusLine.StatusCode); Assert.Equal(reasonPhrase, statusLine.ReasonPhrase); if (headers != null) { Assert.Equal(headers.Count, statusLine.HttpHeaders.Count()); foreach (var header in headers) { Assert.True( statusLine.HttpHeaders.Contains(header.Key), "Parsed header did not contain expected key " + header.Key ); Assert.Equal( header.Value, statusLine.HttpHeaders.GetValues(header.Key).ElementAt(0) ); } } }
public void StatusLineParserNullBuffer() { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize); Assert.NotNull(parser); int bytesConsumed = 0; Assert.ThrowsArgumentNull(() => { parser.ParseBuffer(null, 0, ref bytesConsumed); }, "buffer"); }
public void StatusLineParserNullBuffer() { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize); Assert.NotNull(parser); int bytesConsumed = 0; Assert.ThrowsArgumentNull(() => { parser.ParseBuffer(null, 0, ref bytesConsumed); }, "buffer"); }
private static void ValidateResult( HttpUnsortedResponse statusLine, Version version, HttpStatusCode statusCode, string reasonPhrase ) { Assert.Equal(version, statusLine.Version); Assert.Equal(statusCode, statusLine.StatusCode); Assert.Equal(reasonPhrase, statusLine.ReasonPhrase); }
public void HttpStatusLineParserConstructorTest() { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); Assert.NotNull(statusLine); Assert.ThrowsArgumentGreaterThanOrEqualTo(() => new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize - 1), "maxStatusLineSize", ParserData.MinStatusLineSize.ToString(), ParserData.MinStatusLineSize - 1); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize); Assert.NotNull(parser); Assert.ThrowsArgumentNull(() => { new HttpStatusLineParser(null, ParserData.MinStatusLineSize); }, "httpResponse"); }
public void StatusLineParserRejectsLws() { byte[] data = CreateBuffer("HTTP/1.1", "200", "Reason", true); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, data.Length); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } }
public void StatusLineParserMinimumBuffer() { byte[] data = CreateBuffer("HTTP/1.1", "200", ""); HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize); Assert.NotNull(parser); int bytesConsumed = 0; ParserState state = parser.ParseBuffer(data, data.Length, ref bytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, bytesConsumed); ValidateResult(statusLine, new Version("1.1"), HttpStatusCode.OK, ""); }
public void StatusLineParserRejectsLws() { byte[] data = CreateBuffer("HTTP/1.1", "200", "Reason", true); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, data.Length); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } }
/// <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 new ArgumentNullException("httpResponse"); } _httpResponse = httpResponse; // Create status line parser _statusLineParser = new HttpStatusLineParser(_httpResponse, maxResponseLineSize); // Create header parser _headerParser = new InternetMessageFormatHeaderParser(_httpResponse.HttpHeaders, maxHeaderSize); }
public void ResponseHeaderParserRejectsInvalidVersion(string invalid) { byte[] data = CreateBuffer(invalid, "200", "Reason", ParserData.ValidHeaders); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse result = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(result); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } }
/// <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 new ArgumentNullException("httpResponse"); } _httpResponse = httpResponse; // Create status line parser _statusLineParser = new HttpStatusLineParser(_httpResponse, maxResponseLineSize); // Create header parser _headerParser = new InternetMessageFormatHeaderParser(_httpResponse.HttpHeaders, maxHeaderSize); }
/// <summary> /// Initializes a new instance of the <see cref="HttpStatusLineParser"/> class. /// </summary> /// <param name="httpResponse"><see cref="HttpUnsortedResponse"/> instance where the response line properties will be set as they are parsed.</param> /// <param name="maxStatusLineSize">Maximum length of HTTP header.</param> public HttpStatusLineParser(HttpUnsortedResponse httpResponse, int maxStatusLineSize) { // The minimum length which would be an empty header terminated by CRLF if (maxStatusLineSize < MinStatusLineSize) { throw new ArgumentOutOfRangeException("maxStatusLineSize", maxStatusLineSize, RS.Format(Properties.Resources.ArgumentMustBeGreaterThanOrEqualTo, MinStatusLineSize)); } if (httpResponse == null) { throw new ArgumentNullException("httpResponse"); } _httpResponse = httpResponse; _maximumHeaderLength = maxStatusLineSize; }
/// <summary> /// Initializes a new instance of the <see cref="HttpStatusLineParser"/> class. /// </summary> /// <param name="httpResponse"><see cref="HttpUnsortedResponse"/> instance where the response line properties will be set as they are parsed.</param> /// <param name="maxStatusLineSize">Maximum length of HTTP header.</param> public HttpStatusLineParser(HttpUnsortedResponse httpResponse, int maxStatusLineSize) { // The minimum length which would be an empty header terminated by CRLF if (maxStatusLineSize < MinStatusLineSize) { throw Error.ArgumentMustBeGreaterThanOrEqualTo("maxStatusLineSize", maxStatusLineSize, MinStatusLineSize); } if (httpResponse == null) { throw Error.ArgumentNull("httpResponse"); } this._httpResponse = httpResponse; this._maximumHeaderLength = maxStatusLineSize; }
public void StatusLineParserMinimumBuffer() { byte[] data = CreateBuffer("HTTP/1.1", "200", ""); HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, ParserData.MinStatusLineSize); Assert.NotNull(parser); int bytesConsumed = 0; ParserState state = parser.ParseBuffer(data, data.Length, ref bytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, bytesConsumed); ValidateResult(statusLine, new Version("1.1"), HttpStatusCode.OK, ""); }
/// <summary> /// Initializes a new instance of the <see cref="HttpStatusLineParser"/> class. /// </summary> /// <param name="httpResponse"><see cref="HttpUnsortedResponse"/> instance where the response line properties will be set as they are parsed.</param> /// <param name="maxStatusLineSize">Maximum length of HTTP header.</param> public HttpStatusLineParser(HttpUnsortedResponse httpResponse, int maxStatusLineSize) { // The minimum length which would be an empty header terminated by CRLF if (maxStatusLineSize < MinStatusLineSize) { throw Error.ArgumentMustBeGreaterThanOrEqualTo("maxStatusLineSize", maxStatusLineSize, MinStatusLineSize); } if (httpResponse == null) { throw Error.ArgumentNull("httpResponse"); } this._httpResponse = httpResponse; this._maximumHeaderLength = maxStatusLineSize; }
/// <summary> /// Initializes a new instance of the <see cref="HttpStatusLineParser"/> class. /// </summary> /// <param name="httpResponse"><see cref="HttpUnsortedResponse"/> instance where the response line properties will be set as they are parsed.</param> /// <param name="maxStatusLineSize">Maximum length of HTTP header.</param> public HttpStatusLineParser(HttpUnsortedResponse httpResponse, int maxStatusLineSize) { // The minimum length which would be an empty header terminated by CRLF if (maxStatusLineSize < MinStatusLineSize) { throw new ArgumentOutOfRangeException("maxStatusLineSize", maxStatusLineSize, RS.Format(Properties.Resources.ArgumentMustBeGreaterThanOrEqualTo, MinStatusLineSize)); } if (httpResponse == null) { throw new ArgumentNullException("httpResponse"); } _httpResponse = httpResponse; _maximumHeaderLength = maxStatusLineSize; }
public void StatusLineParserAcceptsValidReasonPhrase(string validReasonPhrase) { byte[] data = CreateBuffer("HTTP/1.1", "200", validReasonPhrase); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, 256); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); ValidateResult(statusLine, new Version("1.1"), HttpStatusCode.OK, validReasonPhrase); } }
public void StatusLineParserAcceptsStandardStatusCodes(HttpStatusCode status) { byte[] data = CreateBuffer("HTTP/1.1", ((int)status).ToString(), "Reason"); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, data.Length); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult(statusLine, new Version("1.1"), status, "Reason"); } }
public void StatusLineParserRejectsInvalidStatusCodes() { foreach (string invalidStatus in ParserData.InvalidStatusCodes) { byte[] data = CreateBuffer("HTTP/1.1", invalidStatus, "Reason"); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, 256); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } } }
private static void ValidateResult( HttpUnsortedResponse statusLine, Version version, HttpStatusCode statusCode, string reasonPhrase, Dictionary<string, string> headers) { Assert.Equal(version, statusLine.Version); Assert.Equal(statusCode, statusLine.StatusCode); Assert.Equal(reasonPhrase, statusLine.ReasonPhrase); if (headers != null) { Assert.Equal(headers.Count, statusLine.HttpHeaders.Count()); foreach (var header in headers) { Assert.True(statusLine.HttpHeaders.Contains(header.Key), "Parsed header did not contain expected key " + header.Key); Assert.Equal(header.Value, statusLine.HttpHeaders.GetValues(header.Key).ElementAt(0)); } } }
public void StatusLineParserAcceptsCustomStatusCodes() { foreach (HttpStatusCode status in HttpUnitTestDataSets.CustomHttpStatusCodes) { byte[] data = CreateBuffer("HTTP/1.1", ((int)status).ToString(), "Reason"); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, data.Length); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult(statusLine, new Version("1.1"), status, "Reason"); } } }
private static ParserState ParseStatusLine( byte[] buffer, int bytesReady, ref int bytesConsumed, ref HttpStatusLineState statusLineState, int maximumHeaderLength, ref int totalBytesConsumed, StringBuilder currentToken, HttpUnsortedResponse httpResponse) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseRequestLine()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumHeaderLength <= 0 || totalBytesConsumed <= maximumHeaderLength, "ParseRequestLine()|Headers already read exceeds limit."); // Remember where we started. int initialBytesParsed = bytesConsumed; int segmentStart; // Set up parsing status with what will happen if we exceed the buffer. ParserState parseStatus = ParserState.DataTooBig; int effectiveMax = maximumHeaderLength <= 0 ? Int32.MaxValue : (maximumHeaderLength - totalBytesConsumed + bytesConsumed); if (bytesReady < effectiveMax) { parseStatus = ParserState.NeedMoreData; effectiveMax = bytesReady; } Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (statusLineState) { case HttpStatusLineState.BeforeVersionNumbers: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '/') { if (buffer[bytesConsumed] < 0x21 || buffer[bytesConsumed] > 0x7a) { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string token = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(token); goto quit; } } if (bytesConsumed > segmentStart) { string token = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(token); } // Validate value string version = currentToken.ToString(); if (String.CompareOrdinal(FormattingUtilities.HttpVersionToken, version) != 0) { throw new FormatException(Error.Format(Resources.HttpInvalidVersion, version, FormattingUtilities.HttpVersionToken)); } currentToken.Clear(); // Move past the '/' statusLineState = HttpStatusLineState.MajorVersionNumber; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.MajorVersionNumber; case HttpStatusLineState.MajorVersionNumber: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '.') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string major = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(major); goto quit; } } if (bytesConsumed > segmentStart) { string major = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(major); } // Move past the "." currentToken.Append('.'); statusLineState = HttpStatusLineState.MinorVersionNumber; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.MinorVersionNumber; case HttpStatusLineState.MinorVersionNumber: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != ' ') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string minor = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(minor); goto quit; } } if (bytesConsumed > segmentStart) { string minor = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(minor); } // Copy out value httpResponse.Version = Version.Parse(currentToken.ToString()); currentToken.Clear(); // Move past the SP statusLineState = HttpStatusLineState.StatusCode; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.StatusCode; case HttpStatusLineState.StatusCode: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != ' ') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string method = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(method); goto quit; } } if (bytesConsumed > segmentStart) { string method = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(method); } // Copy value out int statusCode = Int32.Parse(currentToken.ToString(), CultureInfo.InvariantCulture); if (statusCode < 100 || statusCode > 1000) { throw new FormatException(Error.Format(Resources.HttpInvalidStatusCode, statusCode, 100, 1000)); } httpResponse.StatusCode = (HttpStatusCode)statusCode; currentToken.Clear(); // Move past the SP statusLineState = HttpStatusLineState.ReasonPhrase; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.ReasonPhrase; case HttpStatusLineState.ReasonPhrase: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '\r') { if (buffer[bytesConsumed] < 0x20 || buffer[bytesConsumed] > 0x7a) { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string addr = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(addr); goto quit; } } if (bytesConsumed > segmentStart) { string addr = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(addr); } // Copy value out httpResponse.ReasonPhrase = currentToken.ToString(); currentToken.Clear(); // Move past the CR statusLineState = HttpStatusLineState.AfterCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.AfterCarriageReturn; case HttpStatusLineState.AfterCarriageReturn: if (buffer[bytesConsumed] != '\n') { parseStatus = ParserState.Invalid; goto quit; } parseStatus = ParserState.Done; bytesConsumed++; break; } quit: totalBytesConsumed += bytesConsumed - initialBytesParsed; return(parseStatus); }
public void ResponseHeaderParserRejectsInvalidVersion(string invalid) { byte[] data = CreateBuffer(invalid, "200", "Reason", ParserData.ValidHeaders); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse result = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(result); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } }
public void StatusLineParserRejectsInvalidStatusCodes() { foreach (string invalidStatus in ParserData.InvalidStatusCodes) { byte[] data = CreateBuffer("HTTP/1.1", invalidStatus, "Reason"); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, 256); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Invalid, state); } } }
public void ResponseHeaderParserAcceptsCustomStatusCodes() { foreach (HttpStatusCode status in HttpUnitTestDataSets.CustomHttpStatusCodes) { byte[] data = CreateBuffer("HTTP/1.1", ((int)status).ToString(), "Reason", ParserData.ValidHeaders); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse result = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(result); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(ParserState.Done, state); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult(result, new Version("1.1"), status, "Reason", ParserData.ValidHeaders); } } }
private static void ValidateResult(HttpUnsortedResponse statusLine, Version version, HttpStatusCode statusCode, string reasonPhrase) { Assert.Equal(version, statusLine.Version); Assert.Equal(statusCode, statusLine.StatusCode); Assert.Equal(reasonPhrase, statusLine.ReasonPhrase); }
public void StatusLineParserAcceptsValidVersion(Version version) { byte[] data = CreateBuffer(String.Format("HTTP/{0}", version.ToString(2)), "200", "Reason"); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, 256); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); Assert.Equal(data.Length, totalBytesConsumed); ValidateResult(statusLine, version, HttpStatusCode.OK, "Reason"); } }
public void StatusLineParserAcceptsValidReasonPhrase(string validReasonPhrase) { byte[] data = CreateBuffer("HTTP/1.1", "200", validReasonPhrase); for (var cnt = 1; cnt <= data.Length; cnt++) { HttpUnsortedResponse statusLine = new HttpUnsortedResponse(); HttpStatusLineParser parser = new HttpStatusLineParser(statusLine, 256); Assert.NotNull(parser); int totalBytesConsumed = 0; ParserState state = ParseBufferInSteps(parser, data, cnt, out totalBytesConsumed); ValidateResult(statusLine, new Version("1.1"), HttpStatusCode.OK, validReasonPhrase); } }
private static HttpResponseMessage CreateHttpResponseMessage(HttpUnsortedResponse httpResponse, Stream contentStream, int rewind) { Contract.Assert(httpResponse != null, "httpResponse must be non null"); Contract.Assert(contentStream != null, "contentStream must be non null"); HttpResponseMessage httpResponseMessage = new HttpResponseMessage(); // Set version, status code and reason phrase httpResponseMessage.Version = httpResponse.Version; httpResponseMessage.StatusCode = httpResponse.StatusCode; httpResponseMessage.ReasonPhrase = httpResponse.ReasonPhrase; // Set the header fields and content if any httpResponseMessage.Content = CreateHeaderFields(httpResponse.HttpHeaders, httpResponseMessage.Headers, contentStream, rewind); return httpResponseMessage; }
private static async Task<HttpResponseMessage> ReadAsHttpResponseMessageAsyncCore(this HttpContent content, int bufferSize, int maxHeaderSize, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); Stream stream = await content.ReadAsStreamAsync(); HttpUnsortedResponse httpResponse = new HttpUnsortedResponse(); HttpResponseHeaderParser parser = new HttpResponseHeaderParser(httpResponse, HttpResponseHeaderParser.DefaultMaxStatusLineSize, maxHeaderSize); ParserState parseStatus; byte[] buffer = new byte[bufferSize]; int bytesRead = 0; int headerConsumed = 0; while (true) { try { bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, cancellationToken); } catch (Exception e) { throw new IOException(Resources.HttpMessageErrorReading, e); } try { parseStatus = parser.ParseBuffer(buffer, bytesRead, ref headerConsumed); } catch (Exception) { parseStatus = ParserState.Invalid; } if (parseStatus == ParserState.Done) { // Create and return parsed HttpResponseMessage return CreateHttpResponseMessage(httpResponse, stream, bytesRead - headerConsumed); } else if (parseStatus != ParserState.NeedMoreData) { throw Error.InvalidOperation(Resources.HttpMessageParserError, headerConsumed, buffer); } else if (bytesRead == 0) { throw new IOException(Resources.ReadAsHttpMessageUnexpectedTermination); } } }
/// <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) { }
private static ParserState ParseStatusLine( byte[] buffer, int bytesReady, ref int bytesConsumed, ref HttpStatusLineState statusLineState, int maximumHeaderLength, ref int totalBytesConsumed, StringBuilder currentToken, HttpUnsortedResponse httpResponse) { Contract.Assert((bytesReady - bytesConsumed) >= 0, "ParseRequestLine()|(bytesReady - bytesConsumed) < 0"); Contract.Assert(maximumHeaderLength <= 0 || totalBytesConsumed <= maximumHeaderLength, "ParseRequestLine()|Headers already read exceeds limit."); // Remember where we started. int initialBytesParsed = bytesConsumed; int segmentStart; // Set up parsing status with what will happen if we exceed the buffer. ParserState parseStatus = ParserState.DataTooBig; int effectiveMax = maximumHeaderLength <= 0 ? Int32.MaxValue : (maximumHeaderLength - totalBytesConsumed + bytesConsumed); if (bytesReady < effectiveMax) { parseStatus = ParserState.NeedMoreData; effectiveMax = bytesReady; } Contract.Assert(bytesConsumed < effectiveMax, "We have already consumed more than the max header length."); switch (statusLineState) { case HttpStatusLineState.BeforeVersionNumbers: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '/') { if (buffer[bytesConsumed] < 0x21 || buffer[bytesConsumed] > 0x7a) { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string token = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(token); goto quit; } } if (bytesConsumed > segmentStart) { string token = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(token); } // Validate value string version = currentToken.ToString(); if (String.CompareOrdinal(FormattingUtilities.HttpVersionToken, version) != 0) { throw new FormatException(RS.Format(Properties.Resources.HttpInvalidVersion, version, FormattingUtilities.HttpVersionToken)); } currentToken.Clear(); // Move past the '/' statusLineState = HttpStatusLineState.MajorVersionNumber; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.MajorVersionNumber; case HttpStatusLineState.MajorVersionNumber: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '.') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string major = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(major); goto quit; } } if (bytesConsumed > segmentStart) { string major = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(major); } // Move past the "." currentToken.Append('.'); statusLineState = HttpStatusLineState.MinorVersionNumber; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.MinorVersionNumber; case HttpStatusLineState.MinorVersionNumber: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != ' ') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string minor = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(minor); goto quit; } } if (bytesConsumed > segmentStart) { string minor = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(minor); } // Copy out value httpResponse.Version = Version.Parse(currentToken.ToString()); currentToken.Clear(); // Move past the SP statusLineState = HttpStatusLineState.StatusCode; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.StatusCode; case HttpStatusLineState.StatusCode: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != ' ') { if (buffer[bytesConsumed] < '0' || buffer[bytesConsumed] > '9') { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string method = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(method); goto quit; } } if (bytesConsumed > segmentStart) { string method = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(method); } // Copy value out int statusCode = Int32.Parse(currentToken.ToString(), CultureInfo.InvariantCulture); if (statusCode < 100 || statusCode > 1000) { throw new FormatException(RS.Format(Properties.Resources.HttpInvalidStatusCode, statusCode, 100, 1000)); } httpResponse.StatusCode = (HttpStatusCode)statusCode; currentToken.Clear(); // Move past the SP statusLineState = HttpStatusLineState.ReasonPhrase; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.ReasonPhrase; case HttpStatusLineState.ReasonPhrase: segmentStart = bytesConsumed; while (buffer[bytesConsumed] != '\r') { if (buffer[bytesConsumed] < 0x20 || buffer[bytesConsumed] > 0x7a) { parseStatus = ParserState.Invalid; goto quit; } if (++bytesConsumed == effectiveMax) { string addr = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(addr); goto quit; } } if (bytesConsumed > segmentStart) { string addr = Encoding.UTF8.GetString(buffer, segmentStart, bytesConsumed - segmentStart); currentToken.Append(addr); } // Copy value out httpResponse.ReasonPhrase = currentToken.ToString(); currentToken.Clear(); // Move past the CR statusLineState = HttpStatusLineState.AfterCarriageReturn; if (++bytesConsumed == effectiveMax) { goto quit; } goto case HttpStatusLineState.AfterCarriageReturn; case HttpStatusLineState.AfterCarriageReturn: if (buffer[bytesConsumed] != '\n') { parseStatus = ParserState.Invalid; goto quit; } parseStatus = ParserState.Done; bytesConsumed++; break; } quit: totalBytesConsumed += bytesConsumed - initialBytesParsed; return parseStatus; }
/// <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) { }