You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
186 lines
6.7 KiB
186 lines
6.7 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
|
|
namespace Apewer.Web
|
|
{
|
|
|
|
internal sealed class MiniReader : Stream
|
|
{
|
|
|
|
bool _disposed = false;
|
|
|
|
MiniConnection _connection;
|
|
Stream _stream;
|
|
long _remaining;
|
|
|
|
internal byte[] RemainsBytes = null;
|
|
int _offset = 0;
|
|
long _total = 0L;
|
|
|
|
internal MiniReader(MiniConnection connection, long remaining = -1)
|
|
{
|
|
_connection = connection;
|
|
_stream = connection.Stream;
|
|
_remaining = remaining;
|
|
}
|
|
|
|
public bool Disposed { get => _disposed; }
|
|
|
|
public override bool CanRead { get => true; }
|
|
|
|
public override bool CanWrite { get => false; }
|
|
|
|
public override bool CanSeek { get => false; }
|
|
|
|
public override long Length { get => throw new NotSupportedException(); }
|
|
|
|
public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); }
|
|
|
|
public override void Close() => _disposed = true;
|
|
|
|
public override void Flush() { }
|
|
|
|
public override long Seek(long offset, SeekOrigin origin) => throw new NotSupportedException();
|
|
|
|
public override void SetLength(long value) => throw new NotSupportedException();
|
|
|
|
#region read
|
|
|
|
int ReadRemins(byte[] buffer, int offset, int count)
|
|
{
|
|
// 返回 0,读取 Remains 已经完成,由外层继续读取。
|
|
if (RemainsBytes == null) return 0;
|
|
var length = RemainsBytes.Length;
|
|
if (length < 1) return 0;
|
|
|
|
// Remains 中剩余的长度,并根据 count 参数限制读取数量。
|
|
var result = length - offset;
|
|
if (result < 1) return 0;
|
|
if (result > count) result = count;
|
|
|
|
// Content-Length 指定的剩余长度。
|
|
if (_remaining > 0 && result > _remaining) result = (int)_remaining;
|
|
|
|
// RemainsBytes 长度溢出限制。
|
|
if (result + _offset > length) result = length - _offset;
|
|
|
|
// 从 Remains 中读取,返回具体的字节数。
|
|
Buffer.BlockCopy(RemainsBytes, _offset, buffer, offset, result);
|
|
_offset += result;
|
|
_remaining -= result;
|
|
_total += result;
|
|
|
|
// 已完成 Remains 的读取。
|
|
if (_offset >= length) RemainsBytes = null;
|
|
return result;
|
|
}
|
|
|
|
public override int Read(byte[] buffer, int offset, int count)
|
|
{
|
|
if (_connection.Server.SynchronousIO)
|
|
{
|
|
if (_disposed) throw new ObjectDisposedException(typeof(Stream).FullName);
|
|
|
|
// 检查参数。
|
|
if (buffer == null) throw new ArgumentNullException("参数 buffer 无效。");
|
|
if (offset < 0) throw new ArgumentOutOfRangeException("offset", "参数 offset 小于 0。");
|
|
if (count < 0) throw new ArgumentOutOfRangeException("count", "参数 count 小于 0。");
|
|
int bufferLength = buffer.Length;
|
|
if (offset > bufferLength) throw new ArgumentOutOfRangeException("offset", "指定的 offset 的值超出了 buffer 数组的容量。");
|
|
if (offset + count > bufferLength) throw new ArgumentException("指定的 offset 和 count 超出了 buffer 数组的容量。");
|
|
if (count == 0) return 0;
|
|
|
|
// 检查剩余读取量。
|
|
if (_remaining == 0) return 0;
|
|
|
|
// 从 Remains 中读取。
|
|
var nread = ReadRemins(buffer, offset, count);
|
|
if (nread > 0) return nread;
|
|
|
|
// 根据 Content-Length 限定长度。
|
|
if (_remaining > 0 && _remaining < count) count = (int)_remaining;
|
|
|
|
var read = _stream.Read(buffer, offset, count);
|
|
if (read > 0 && _remaining > 0) _remaining -= read;
|
|
return read;
|
|
}
|
|
else
|
|
{
|
|
var async = BeginRead(buffer, offset, count, null, null);
|
|
var result = EndRead(async);
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback cback, object state)
|
|
{
|
|
#if DEBUG
|
|
if (_disposed) throw new ObjectDisposedException(typeof(Stream).FullName);
|
|
|
|
// 检查参数。
|
|
if (buffer == null) throw new ArgumentNullException("参数 buffer 无效。");
|
|
if (offset < 0) throw new ArgumentOutOfRangeException("offset", "参数 offset 小于 0。");
|
|
if (count < 0) throw new ArgumentOutOfRangeException("count", "参数 count 小于 0。");
|
|
int bufferLength = buffer.Length;
|
|
if (offset > bufferLength) throw new ArgumentOutOfRangeException("offset", "指定的 offset 的值超出了 buffer 数组的容量。");
|
|
if (offset + count > bufferLength) throw new ArgumentException("指定的 offset 和 count 超出了 buffer 数组的容量。");
|
|
|
|
// Content-Length
|
|
if (_remaining == 0)
|
|
{
|
|
var ares = new MiniStreamAsyncResult();
|
|
ares.Buffer = buffer;
|
|
ares.Offset = offset;
|
|
ares.Count = count;
|
|
ares.Callback = cback;
|
|
ares.State = state;
|
|
ares.SynchRead = 0;
|
|
ares.Complete();
|
|
return ares;
|
|
}
|
|
if (_remaining > 0 && _remaining < count) count = (int)_remaining;
|
|
|
|
return _stream.BeginRead(buffer, offset, count, cback, state);
|
|
#else
|
|
throw new NotSupportedException();
|
|
#endif
|
|
}
|
|
|
|
public override int EndRead(IAsyncResult ar)
|
|
{
|
|
#if DEBUG
|
|
if (_disposed) throw new ObjectDisposedException(typeof(Stream).FullName);
|
|
if (ar == null) throw new ArgumentNullException(nameof(ar));
|
|
|
|
if (ar is MiniStreamAsyncResult)
|
|
{
|
|
var r = (MiniStreamAsyncResult)ar;
|
|
if (!ar.IsCompleted) ar.AsyncWaitHandle.WaitOne();
|
|
return r.SynchRead;
|
|
}
|
|
|
|
int nread = _stream.EndRead(ar);
|
|
if (_remaining > 0 && nread > 0) _remaining -= nread;
|
|
return nread;
|
|
#else
|
|
throw new NotSupportedException();
|
|
#endif
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region write
|
|
|
|
public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException();
|
|
|
|
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) => throw new NotSupportedException();
|
|
|
|
public override void EndWrite(IAsyncResult ar) => throw new NotSupportedException();
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|