// 
 | 
// 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) 
 | 
        { 
 | 
            throw new NotSupportedException (); 
 | 
        } 
 | 
  
 | 
        public override void EndWrite (IAsyncResult async_result) 
 | 
        { 
 | 
            throw new NotSupportedException (); 
 | 
        } 
 | 
    } 
 | 
} 
 |