#region CPL License
/*
Nuclex Framework
Copyright (C) 2002-2009 Nuclex Development Labs
This library is free software; you can redistribute it and/or
modify it under the terms of the IBM Common Public License as
published by the IBM Corporation; either version 1.0 of the
License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
IBM Common Public License for more details.
You should have received a copy of the IBM Common Public
License along with this library
*/
#endregion
#if UNITTEST
using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace Nuclex.Networking.Http {
/// Unit tests for the HTTP request parser
[TestFixture]
public class HttpLineParserTest {
#region class TestParser
/// Dummy parser for testing the HTTP request line parser
private class TestParser : HttpLineParser {
/// Initializes a new test parser
///
/// Maximum size the HTTP request header is allowed to have
///
public TestParser(int maximumHeaderSize) : base(maximumHeaderSize) { }
/// Adds bytes to be parsed
/// Array containing the bytes to be parsed
/// Index at which to begin reading the array
/// Number of bytes to take from the array
/// True if more data is required
public void AddBytes(byte[] bytes, int start, int count) {
SetReceivedData(bytes, start, count);
for(; ; ) {
string line = ParseLine();
if(line == null) {
break;
}
}
}
}
#endregion // class TestParser
///
/// Tests whether a buffer overflow in a single adds is handled correctly
///
[Test]
public void TestBufferOverflowSingleRun() {
TestParser parser = new TestParser(128);
Assert.Throws(
delegate() { parser.AddBytes(createWhiteSpaceArray(129), 0, 129); }
);
}
///
/// Tests whether a buffer overflow built over multiple adds is handled correctly
///
[Test]
public void TestBufferOverflowMultipleRuns() {
TestParser parser = new TestParser(128);
parser.AddBytes(createWhiteSpaceArray(100), 0, 100);
Assert.Throws(
delegate() { parser.AddBytes(createWhiteSpaceArray(29), 0, 29); }
);
}
///
/// Tests whether a line containing invalid characters is rejected
///
[Test]
public void TestInvalidCharactersInRequest() {
TestParser parser = new TestParser(128);
byte[] requestData = Encoding.ASCII.GetBytes("GET /something HTTP/1.1\r\n");
requestData[6] = 10;
requestData[9] = 13;
Assert.Throws(
delegate() { parser.AddBytes(requestData, 0, requestData.Length); }
);
}
///
/// Tests whether a line end is recognized when it is split into two adds
///
///
/// If the line end is not correctly recognized, a BadRequestException will result
///
[Test]
public void TestSplitLineEndRecognition() {
TestParser parser = new TestParser(128);
byte[] requestData = Encoding.ASCII.GetBytes(exampleRequest);
int crIndex = Array.IndexOf(requestData, 13);
System.Diagnostics.Trace.Assert(crIndex != -1);
parser.AddBytes(requestData, 0, crIndex + 1);
Assert.Throws(
delegate() {
parser.AddBytes(requestData, crIndex + 1, requestData.Length - crIndex);
}
);
}
/// Make sure the parser correctly handles the array start index
[Test]
public void TestExampleRequestWithStartIndex() {
TestParser parser = new TestParser(512);
byte[] requestData = Encoding.ASCII.GetBytes(exampleRequest);
byte[] paddedRequestData = createWhiteSpaceArray(requestData.Length + 512);
Array.Copy(requestData, 0, paddedRequestData, 512, requestData.Length);
parser.AddBytes(paddedRequestData, 512, requestData.Length);
}
/// Tests whether the parser can handle a normal HTTP request
[Test]
public void TestExampleRequest() {
TestParser parser = new TestParser(512);
byte[] requestData = Encoding.ASCII.GetBytes(exampleRequest);
parser.AddBytes(requestData, 0, requestData.Length);
}
/// Creates a byte array of whitespace characters
/// Number of whitespace characters to put in the array
/// The array of whitespace characters
public static byte[] createWhiteSpaceArray(int length) {
return Encoding.ASCII.GetBytes(new string(' ', length));
}
/// An example HTTP/1.1 request
private static readonly string exampleRequest =
"GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.8.1.16)" +
"Gecko/20080702 Firefox/2.0.0.16\r\n" +
"Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;" +
"q=0.8,image/png,*/*;q=0.5\r\n" +
"Accept-Language: de-de,de;q=0.8,en-us;q=0.5,en;q=0.3\r\n" +
"Accept-Encoding: gzip,deflate\r\n" +
"Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n" +
"Keep-Alive: 300\r\n" +
"Connection: keep-alive\r\n" +
"Cache-Control: max-age=0\r\n" +
"\r\n";
}
} // namespace Nuclex.Networking.Http
#endif // UNITTEST