failing at a simple MessageEncoder

N

not_a_commie

I was trying to write my own MessageEncoder but I can't even
deserialize a message body. Can somebody fill in the comment
(containing FREAK) in the code below? Thanks.

[Test]
public void TestEncoder()
{
var rand = new Random(1);
var points = 10;
var list1 = new List<int>(points);
for (int i = 0; i < points; i++)
list1.Add(rand.Next() >> 4); // at least 4 compressable bits out of
32!
var msg = Message.CreateMessage(MessageVersion.Default, "*", list1);

var bufMgr = BufferManager.CreateBufferManager(int.MaxValue,
1<<25); // 32MB
var encoder = new
CompressionEncoderFactory.CompressionEncoder(CompressionMode.Deflate,
new BasicMessageEncoder());
var arr = encoder.WriteMessage(msg, int.MaxValue, bufMgr, 0);
var res = encoder.ReadMessage(arr, bufMgr);

var list2 = res.GetBody<List<int>>();
for (int i = 0; i < points; i++)
Assert.AreEqual(list1, list2);
}

internal class BasicMessageEncoder : MessageEncoder
{
public override Message ReadMessage(Stream stream, int
maxSizeOfHeaders, string contentType)
{
using (var reader = XmlDictionaryReader.CreateTextReader(stream,
Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null))
return Message.CreateMessage(reader, maxSizeOfHeaders,
MessageVersion);
}

public override Message ReadMessage(ArraySegment<byte> buffer,
BufferManager bufferManager, string contentType)
{
Message header, full;
using (var reader =
XmlDictionaryReader.CreateTextReader(buffer.Array, buffer.Offset,
buffer.Count, Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null))
{
header = Message.CreateMessage(reader, int.MaxValue,
MessageVersion);
// WHAT the FREAK goes here to fill in the message body? the above
only reads the headers...
}
bufferManager.ReturnBuffer(buffer.Array);
return full;
}

public override void WriteMessage(Message message, Stream stream)
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(stream,
Encoding.UTF8, false))
message.WriteMessage(writer);
}

public override ArraySegment<byte> WriteMessage(Message message, int
maxMessageSize, BufferManager bufferManager, int messageOffset)
{
ArraySegment<byte> ret;
using (var stream = new MemoryStream())
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(stream,
Encoding.UTF8, false))
message.WriteMessage(writer);

var bytes = stream.ToArray();
var buffer = bufferManager.TakeBuffer(bytes.Length +
messageOffset);
Array.Copy(bytes, 0, buffer, messageOffset, bytes.Length);
ret = new ArraySegment<byte>(buffer, messageOffset, bytes.Length);
}
return ret;
}

public override string ContentType
{
get { return "application/soap"; }
}

public override string MediaType
{
get { return "application/soap"; }
}

public override MessageVersion MessageVersion
{
get { return MessageVersion.Default; }
}
}
 
N

not_a_commie

I did get this issue figured out. The problem was that the Message
class doesn't actually use the readers passed into
Message.CreateMessage until someone attempts to read the data from the
body of the message. Creating a copy is one way to force the read. See
my updated code below:

internal class BasicMessageEncoder : MessageEncoder
{
public override Message ReadMessage(Stream stream, int
maxSizeOfHeaders, string contentType)
{
using (var reader = XmlDictionaryReader.CreateTextReader(stream,
Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null))
{
// this is really lame in that it just stores this reader unless
you actually make a copy of the message
// in which case it copies the data from the reader
return Message.CreateMessage(reader, int.MaxValue,
MessageVersion).CreateBufferedCopy(int.MaxValue).CreateMessage();
}
}

public override Message ReadMessage(ArraySegment<byte> buffer,
BufferManager bufferManager, string contentType)
{
Message ret;
using (var reader =
XmlDictionaryReader.CreateTextReader(buffer.Array, buffer.Offset,
buffer.Count, Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null))
{
// this is really lame in that it just stores this reader unless
you actually make a copy of the message
// in which case it copies the data from the reader
ret = Message.CreateMessage(reader, int.MaxValue,
MessageVersion).CreateBufferedCopy(int.MaxValue).CreateMessage();
}
bufferManager.ReturnBuffer(buffer.Array);
return ret;
}

public override void WriteMessage(Message message, Stream stream)
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(stream,
Encoding.UTF8, false))
{
message.WriteMessage(writer);
stream.Flush(); // MSDN said to do this
}
}

public override ArraySegment<byte> WriteMessage(Message message, int
maxMessageSize, BufferManager bufferManager, int messageOffset)
{
ArraySegment<byte> ret;
using (var stream = new MemoryStream())
{
using (var writer = XmlDictionaryWriter.CreateTextWriter(stream,
Encoding.UTF8, false))
message.WriteMessage(writer);

var bytes = stream.ToArray();
var buffer = bufferManager.TakeBuffer(bytes.Length +
messageOffset);
Array.Copy(bytes, 0, buffer, messageOffset, bytes.Length);
ret = new ArraySegment<byte>(buffer, messageOffset, bytes.Length);
}
return ret;
}

public override string ContentType
{
get { return "application/soap"; }
}

public override string MediaType
{
get { return "application/soap"; }
}

public override MessageVersion MessageVersion
{
get { return MessageVersion.Default; }
}
}
 
N

not_a_commie

I had forgotten those message classes were all disposable. I had to
modify things a bit:

using (var reader = XmlDictionaryReader.CreateTextReader(stream,
Encoding.UTF8, XmlDictionaryReaderQuotas.Max, null))
using (var msg = Message.CreateMessage(reader, int.MaxValue,
MessageVersion))
using (var buf = msg.CreateBufferedCopy(int.MaxValue))
return buf.CreateMessage();
 
Top