using System; using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; namespace Cryville.Common.Network { public abstract class HttpResponseStream : Stream { public override bool CanRead { get { return true; } } public override bool CanSeek { get { return false; } } public override bool CanWrite { get { return false; } } public override long Length { get { throw new NotSupportedException(); } } public override long Position { get { throw new NotSupportedException(); } set { throw new NotSupportedException(); } } public override void Flush() { // Do nothing } public abstract byte[] ReadToEnd(); public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } public override void SetLength(long value) { throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } } internal sealed class HttpResponseBlockStream : HttpResponseStream { readonly BinaryReader _reader; readonly int _length; int _pos = 0; internal HttpResponseBlockStream(BinaryReader reader, int length) { _reader = reader; _length = length; } public override int Read(byte[] buffer, int offset, int count) { int recv = 0; int recv_len = System.Math.Min(count, _length - _pos); if (recv_len == 0) return 0; while (recv < recv_len) { recv += _reader.Read(buffer, offset + recv, count - recv); Logger.Log("main", 0, "Network", "Message body received: {0}/{1}/{2}", recv, recv_len, _length); } _pos += recv_len; return recv_len; } public override byte[] ReadToEnd() { byte[] buffer = new byte[_length - _pos]; Read(buffer, 0, buffer.Length); return buffer; } } internal sealed class HttpResponseChunkedStream : HttpResponseStream { readonly BinaryReader _reader; byte[] _chunk = null; int _pos = 0; internal HttpResponseChunkedStream(BinaryReader reader) { _reader = reader; ReadChunk(); } public void ReadChunk() { if (_chunk != null && _chunk.Length == 0) return; string[] chunkHeader = HttpResponse.ReadLine(_reader).Split(';'); // int chunkSize = Array.IndexOf(LEN, chunkHeader[0].ToLower()[0]); int chunkSize = int.Parse(chunkHeader[0], NumberStyles.HexNumber); if (chunkSize == -1) throw new IOException("Corrupted chunk received"); if (chunkSize == 0) { _chunk = new byte[0]; // TODO TE Header, now just discard var headers = new Dictionary(); while (HttpResponse.ParseHeader(_reader, headers)) ; return; } _chunk = new byte[chunkSize]; int recv = 0; while (recv < chunkSize) { recv += _reader.Read(_chunk, recv, chunkSize - recv); Logger.Log("main", 0, "Network", "Message chunk received: {0}/{1}", recv, chunkSize); } _pos = 0; if (HttpResponse.ReadLine(_reader) != "") throw new IOException("Corrupted chunk received"); } public override int Read(byte[] buffer, int offset, int count) { if (_chunk.Length == 0) return 0; int recv = 0; while (true) { if (count - recv <= _chunk.Length - _pos) break; Array.Copy(_chunk, _pos, buffer, recv, _chunk.Length - _pos); recv += _chunk.Length - _pos; ReadChunk(); if (_chunk.Length == 0) return recv; } Array.Copy(_chunk, _pos, buffer, recv, count - recv); return count; } public override byte[] ReadToEnd() { if (_chunk.Length == 0) return new byte[0]; List segs = new List(); while (true) { if (_pos != 0) { var buffer = new byte[_chunk.Length - _pos]; Array.Copy(_chunk, _pos, buffer, 0, buffer.Length); segs.Add(buffer); } else segs.Add(_chunk); ReadChunk(); if (_chunk.Length == 0) { var result = new byte[segs.Sum(i => i.Length)]; int p = 0; foreach (var i in segs) { Array.Copy(i, 0, result, p, i.Length); p += i.Length; } return result; } } } } }