Commit 65032c0f authored by Brickner_cp's avatar Brickner_cp

Simple HTTP Header fields

parent 36d1d759
using System;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PcapDotNet.Base;
using PcapDotNet.Packets.Ethernet;
using PcapDotNet.Packets.Http;
using PcapDotNet.Packets.IpV4;
......@@ -55,8 +57,59 @@ namespace PcapDotNet.Packets.Test
TestHttpRequest("GET /url HTTP/1.1", "GET", "/url");
TestHttpRequest("GET HTTP/1.1", "GET", "", HttpVersion.Version11);
TestHttpRequest("GET /url HTTP/1.1\r\nCache-Control: no-cache", "GET", "/url", HttpVersion.Version11,
new HttpHeader(HttpField.Create("Cache-Control", Encoding.ASCII.GetBytes("no-cache"))));
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"Cache-Control: no-cache\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("Cache-Control", "no-cache")));
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A:B\r\n" +
"B: C\r\n" +
"C: \r\n \r\n D\r\n" +
"D: E\r\n" +
"D: F\r\n" +
"E: G,H\r\n" +
"E: I,J\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("A", "B"),
new HttpField("B", "C"),
new HttpField("C", "D"),
new HttpField("D", "E,F"),
new HttpField("E", "G,H,I,J")));
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"\r\n" +
"A: B\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader());
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A: B\r\n" +
"\r\n" +
"B: C\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("A", "B")));
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A: B\r\n" +
"abc\r\n" +
"B: C\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("A", "B")));
TestHttpRequest("GET /url HTTP/1.1\r\n" +
"A: B\r\n" +
"abc:\r\n" +
"B: C\r\n",
"GET", "/url", HttpVersion.Version11,
new HttpHeader(
new HttpField("A", "B"),
new HttpField("abc", ""),
new HttpField("B", "C")));
TestHttpResponse("HTTP/");
TestHttpResponse("HTTP/1");
......@@ -70,6 +123,12 @@ namespace PcapDotNet.Packets.Test
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, "OK");
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11);
TestHttpResponse("HTTP/1.1 200 OK", HttpVersion.Version11, 200, " OK");
TestHttpResponse("HTTP/1.1 200 OK\r\n" +
"Cache-Control: no-cache\r\n",
HttpVersion.Version11, 200, "OK",
new HttpHeader(
new HttpField("Cache-Control", "no-cache")));
}
private static void TestHttpRequest(string httpString, string expectedMethod = null, string expectedUri = null, HttpVersion expectedVersion = null, HttpHeader expectedHeader = null)
......@@ -91,7 +150,7 @@ namespace PcapDotNet.Packets.Test
// Assert.IsNotNull(header);
}
private static void TestHttpResponse(string httpString, HttpVersion expectedVersion = null, uint? expectedStatusCode = null, string expectedReasonPhrase = null)
private static void TestHttpResponse(string httpString, HttpVersion expectedVersion = null, uint? expectedStatusCode = null, string expectedReasonPhrase = null, HttpHeader expectedHeader = null)
{
Packet packet = BuildPacket(httpString);
......@@ -100,6 +159,7 @@ namespace PcapDotNet.Packets.Test
Assert.IsFalse(http.IsRequest, "IsRequest " + httpString);
Assert.IsTrue(http.IsResponse, "IsResponse " + httpString);
Assert.AreEqual(expectedVersion, http.Version, "Version " + httpString);
Assert.AreEqual(expectedHeader, http.Header, "Header " + httpString);
HttpResponseDatagram response = (HttpResponseDatagram)http;
Assert.AreEqual(expectedStatusCode, response.StatusCode, "StatusCode " + httpString);
......
......@@ -262,7 +262,7 @@ namespace PcapDotNet.Packets.Http
{
string fieldName;
IEnumerable<byte> fieldValue;
parser.Token(out fieldName).Colon().FieldValue(out fieldValue);
parser.Token(out fieldName).Colon().FieldValue(out fieldValue).CarraigeReturnLineFeed();
if (parser.Success)
yield return new KeyValuePair<string, IEnumerable<byte>>(fieldName, fieldValue);
}
......
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using PcapDotNet.Base;
namespace PcapDotNet.Packets.Http
{
public class HttpField : IEquatable<HttpField>
{
public static HttpField Create(string name, IEnumerable<byte> value)
public HttpField(string name, string value)
: this(name, value, _defaultEncoding)
{
}
public HttpField(string name, string value, Encoding encoding)
: this(name, encoding.GetBytes(value))
{
}
public HttpField(string name, IEnumerable<byte> value)
: this(name, value.ToArray())
{
}
public HttpField(string name, IList<byte> value)
:this(name, value.AsReadOnly())
{
switch (name)
{
// general-header
case "Cache-Control":
return new HttpCommaSeparatedField(name, value);
case "Connection":
case "Date":
case "Pragma":
case "Trailer":
case "Transfer-Encoding":
case "Upgrade":
case "Via":
case "Warning":
break;
}
return new HttpField(name);
}
public HttpField(string name, ReadOnlyCollection<byte> value)
{
Name = name;
Value = value;
}
// public static HttpField Create(string name, byte[] value)
// {
// switch (name)
// {
// general-header
// case "Cache-Control":
// return new HttpCommaSeparatedField(name, value);
// case "Connection":
// case "Date":
// case "Pragma":
// case "Trailer":
// case "Transfer-Encoding":
// case "Upgrade":
// case "Via":
// case "Warning":
// break;
// }
//
// return new HttpField(name);
// }
public string Name { get; private set; }
public ReadOnlyCollection<byte> Value { get; private set; }
public bool Equals(HttpField other)
{
return other != null && Name.Equals(other.Name);
return other != null && Name.Equals(other.Name) && Value.SequenceEqual(other.Value);
}
public override bool Equals(object obj)
......@@ -40,12 +70,9 @@ namespace PcapDotNet.Packets.Http
public override string ToString()
{
return string.Format("{0}: ", Name);
return string.Format("{0}: {1}", Name, _defaultEncoding.GetString(Value.ToArray()));
}
internal HttpField(string name)
{
Name = name;
}
private static readonly Encoding _defaultEncoding = Encoding.GetEncoding(28591);
}
}
\ No newline at end of file
......@@ -47,10 +47,10 @@ namespace PcapDotNet.Packets.Http
mergedFields.Add(fieldName, fieldValue);
}
else
mergedFields[fieldName] = fieldValue.Concat(AsciiBytes.Space).Concat(fieldValue);
mergedFields[fieldName] = fieldValue.Concat(AsciiBytes.Comma).Concat(field.Value);
}
_fields = mergedFields.ToDictionary(field => field.Key, field => HttpField.Create(field.Key, field.Value));
_fields = mergedFields.ToDictionary(field => field.Key, field => new HttpField(field.Key, field.Value));
}
public IEnumerator<HttpField> GetEnumerator()
......
......@@ -8,6 +8,11 @@ namespace PcapDotNet.Packets.Http
{
internal class HttpParser
{
public HttpParser(byte[] buffer)
:this(buffer, 0, buffer.Length)
{
}
public HttpParser(byte[] buffer, int offset, int length)
{
_buffer = buffer;
......@@ -43,31 +48,6 @@ namespace PcapDotNet.Packets.Http
return this;
}
private HttpParser Bytes(byte value)
{
if (!Success)
return this;
var range = Range;
if (!range.Any() || range.First() != value)
return Fail();
++_offset;
return this;
}
private HttpParser Bytes(params byte[] values)
{
if (!Success)
return this;
if (!Range.Take(values.Length).SequenceEqual(values))
return Fail();
_offset += values.Length;
return this;
}
public HttpParser Colon()
{
return Bytes(AsciiBytes.Colon);
......@@ -83,8 +63,6 @@ namespace PcapDotNet.Packets.Http
return Bytes(AsciiBytes.Space);
}
public HttpParser SkipLws()
{
while (true)
......@@ -150,17 +128,6 @@ namespace PcapDotNet.Packets.Http
return this;
}
private HttpParser Fail()
{
Success = false;
return this;
}
private IEnumerable<byte> Range
{
get { return _buffer.Range(_offset, _totalLength - _offset); }
}
public HttpParser RequestUri(out string uri)
{
if (!Success)
......@@ -248,12 +215,57 @@ namespace PcapDotNet.Packets.Http
return this;
}
int reasonPhraseLength = Range.Count(value => !value.IsControl() || value == AsciiBytes.HorizontalTab);
int count = 0;
foreach (byte b in Range)
{
if (!b.IsControl() || b == AsciiBytes.HorizontalTab)
++count;
else
break;
}
Console.WriteLine(count);
int reasonPhraseLength = Range.TakeWhile(value => !value.IsControl() || value == AsciiBytes.HorizontalTab).Count();
reasonPhrase = new Datagram(_buffer, _offset, reasonPhraseLength);
_offset += reasonPhraseLength;
return this;
}
private HttpParser Fail()
{
Success = false;
return this;
}
private IEnumerable<byte> Range
{
get { return _buffer.Range(_offset, _totalLength - _offset); }
}
private HttpParser Bytes(byte value)
{
if (!Success)
return this;
var range = Range;
if (!range.Any() || range.First() != value)
return Fail();
++_offset;
return this;
}
private HttpParser Bytes(params byte[] values)
{
if (!Success)
return this;
if (!Range.Take(values.Length).SequenceEqual(values))
return Fail();
_offset += values.Length;
return this;
}
private static readonly byte[] _httpSlash = Encoding.ASCII.GetBytes("HTTP/");
private readonly byte[] _buffer;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment