135 lines
3.9 KiB
C#
135 lines
3.9 KiB
C#
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<string, string>();
|
|
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<byte[]> segs = new List<byte[]>();
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |