context: //
  // RequestStream.cs
  //	Copied from System.Net.RequestStream
  //
  // Author:
  //	Gonzalo Paniagua Javier (gonzalo@novell.com)
  //
  // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
  //
  // Permission is hereby granted, free of charge, to any person obtaining
  // a copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to
  // permit persons to whom the Software is furnished to do so, subject to
  // the following conditions:
  // 
  // The above copyright notice and this permission notice shall be
  // included in all copies or substantial portions of the Software.
  // 
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  //
  
  using System;
  using System.IO;
  using System.Net;
  using System.Net.Sockets;
  using System.Runtime.InteropServices;
  
  namespace WebSocketSharp.Net {
  
  	class RequestStream : Stream
  	{
  		byte [] buffer;
  		int offset;
  		int length;
  		long remaining_body;
  		bool disposed;
  		System.IO.Stream stream;
  
  		internal RequestStream (System.IO.Stream stream, byte [] buffer, int offset, int length)
  			: this (stream, buffer, offset, length, -1)
  		{
  		}
  
  		internal RequestStream (System.IO.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 (); }
  		}
  
  
  		public override void Close ()
  		{
  			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 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 = 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)
  		{
  
gt: 			throw new NotSupportedException ();