aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener.Portable/Net/RequestStream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'SocketHttpListener.Portable/Net/RequestStream.cs')
-rw-r--r--SocketHttpListener.Portable/Net/RequestStream.cs231
1 files changed, 231 insertions, 0 deletions
diff --git a/SocketHttpListener.Portable/Net/RequestStream.cs b/SocketHttpListener.Portable/Net/RequestStream.cs
new file mode 100644
index 000000000..58030500d
--- /dev/null
+++ b/SocketHttpListener.Portable/Net/RequestStream.cs
@@ -0,0 +1,231 @@
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace SocketHttpListener.Net
+{
+ class RequestStream : Stream
+ {
+ byte[] buffer;
+ int offset;
+ int length;
+ long remaining_body;
+ bool disposed;
+ Stream stream;
+
+ internal RequestStream(Stream stream, byte[] buffer, int offset, int length)
+ : this(stream, buffer, offset, length, -1)
+ {
+ }
+
+ internal RequestStream(Stream stream, byte[] buffer, int offset, int length, long contentlength)
+ {
+ this.stream = stream;
+ this.buffer = buffer;
+ this.offset = offset;
+ this.length = length;
+ this.remaining_body = contentlength;
+ }
+
+ 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(); }
+ }
+
+
+ protected override void Dispose(bool disposing)
+ {
+ disposed = true;
+ }
+
+ public override void Flush()
+ {
+ }
+
+
+ // Returns 0 if we can keep reading from the base stream,
+ // > 0 if we read something from the buffer.
+ // -1 if we had a content length set and we finished reading that many bytes.
+ int FillFromBuffer(byte[] buffer, int off, int count)
+ {
+ if (buffer == null)
+ throw new ArgumentNullException("buffer");
+ if (off < 0)
+ throw new ArgumentOutOfRangeException("offset", "< 0");
+ if (count < 0)
+ throw new ArgumentOutOfRangeException("count", "< 0");
+ int len = buffer.Length;
+ if (off > len)
+ throw new ArgumentException("destination offset is beyond array size");
+ if (off > len - count)
+ throw new ArgumentException("Reading would overrun buffer");
+
+ if (this.remaining_body == 0)
+ return -1;
+
+ if (this.length == 0)
+ return 0;
+
+ int size = Math.Min(this.length, count);
+ if (this.remaining_body > 0)
+ size = (int)Math.Min(size, this.remaining_body);
+
+ if (this.offset > this.buffer.Length - size)
+ {
+ size = Math.Min(size, this.buffer.Length - this.offset);
+ }
+ if (size == 0)
+ return 0;
+
+ Buffer.BlockCopy(this.buffer, this.offset, buffer, off, size);
+ this.offset += size;
+ this.length -= size;
+ if (this.remaining_body > 0)
+ remaining_body -= size;
+ return size;
+ }
+
+ public override int Read([In, Out] byte[] buffer, int offset, int count)
+ {
+ if (disposed)
+ throw new ObjectDisposedException(typeof(RequestStream).ToString());
+
+ // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
+ int nread = FillFromBuffer(buffer, offset, count);
+ if (nread == -1)
+ { // No more bytes available (Content-Length)
+ return 0;
+ }
+ else if (nread > 0)
+ {
+ return nread;
+ }
+
+ nread = stream.Read(buffer, offset, count);
+ if (nread > 0 && remaining_body > 0)
+ remaining_body -= nread;
+ return nread;
+ }
+
+ public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
+ {
+ if (disposed)
+ throw new ObjectDisposedException(typeof(RequestStream).ToString());
+
+ int nread = FillFromBuffer(buffer, offset, count);
+ if (nread > 0 || nread == -1)
+ {
+ return Math.Max(0, nread);
+ }
+
+ // Avoid reading past the end of the request to allow
+ // for HTTP pipelining
+ if (remaining_body >= 0 && count > remaining_body)
+ count = (int)Math.Min(Int32.MaxValue, remaining_body);
+
+ nread = await stream.ReadAsync(buffer, offset, count, cancellationToken).ConfigureAwait(false);
+ if (remaining_body > 0 && nread > 0)
+ remaining_body -= nread;
+ return nread;
+ }
+
+ //public override IAsyncResult BeginRead(byte[] buffer, int offset, int count,
+ // AsyncCallback cback, object state)
+ //{
+ // if (disposed)
+ // throw new ObjectDisposedException(typeof(RequestStream).ToString());
+
+ // int nread = FillFromBuffer(buffer, offset, count);
+ // if (nread > 0 || nread == -1)
+ // {
+ // HttpStreamAsyncResult ares = new HttpStreamAsyncResult();
+ // ares.Buffer = buffer;
+ // ares.Offset = offset;
+ // ares.Count = count;
+ // ares.Callback = cback;
+ // ares.State = state;
+ // ares.SynchRead = Math.Max(0, nread);
+ // ares.Complete();
+ // return ares;
+ // }
+
+ // // Avoid reading past the end of the request to allow
+ // // for HTTP pipelining
+ // if (remaining_body >= 0 && count > remaining_body)
+ // count = (int)Math.Min(Int32.MaxValue, remaining_body);
+ // return stream.BeginRead(buffer, offset, count, cback, state);
+ //}
+
+ //public override int EndRead(IAsyncResult ares)
+ //{
+ // if (disposed)
+ // throw new ObjectDisposedException(typeof(RequestStream).ToString());
+
+ // if (ares == null)
+ // throw new ArgumentNullException("async_result");
+
+ // if (ares is HttpStreamAsyncResult)
+ // {
+ // HttpStreamAsyncResult r = (HttpStreamAsyncResult)ares;
+ // if (!ares.IsCompleted)
+ // ares.AsyncWaitHandle.WaitOne();
+ // return r.SynchRead;
+ // }
+
+ // // Close on exception?
+ // int nread = stream.EndRead(ares);
+ // if (remaining_body > 0 && nread > 0)
+ // remaining_body -= nread;
+ // return nread;
+ //}
+
+ 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();
+ }
+
+ //public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count,
+ // AsyncCallback cback, object state)
+ //{
+ // throw new NotSupportedException();
+ //}
+
+ //public override void EndWrite(IAsyncResult async_result)
+ //{
+ // throw new NotSupportedException();
+ //}
+ }
+}