public static string NoTrimReadTo(Stream stream, byte blocker1, byte blocker2)
        {
            byte[] readBuf = VariableSizedBufferPool.Get(1024, true);
            try {
                int bufpos = 0;

                int ch = stream.ReadByte();
                while (ch != blocker1 && ch != blocker2 && ch != -1)
                {
                    if (ch > 0x7f) //replaces asciitostring
                    {
                        ch = '?';
                    }

                    //make buffer larger if too short
                    if (readBuf.Length <= bufpos)
                    {
                        VariableSizedBufferPool.Resize(ref readBuf, readBuf.Length * 2, true);
                    }

                    if (bufpos > 0 || !char.IsWhiteSpace((char)ch)) //trimstart
                    {
                        readBuf[bufpos++] = (byte)ch;
                    }
                    ch = stream.ReadByte();
                }

                return(System.Text.Encoding.UTF8.GetString(readBuf, 0, bufpos));
            }
            finally
            {
                VariableSizedBufferPool.Release(readBuf);
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Assembles all fragments into a final frame. Call this on the last fragment of a frame.
        /// </summary>
        /// <param name="fragments">The list of previously downloaded and parsed fragments of the frame</param>
        public void Assemble(List <WebSocketFrameReader> fragments)
        {
            // this way the following algorithms will handle this fragment's data too
            fragments.Add(this);

            UInt64 finalLength = 0;

            for (int i = 0; i < fragments.Count; ++i)
            {
                finalLength += fragments[i].Length;
            }

            byte[] buffer = fragments[0].Type == WebSocketFrameTypes.Text ? VariableSizedBufferPool.Get((long)finalLength, true) : new byte[finalLength];
            UInt64 pos    = 0;

            for (int i = 0; i < fragments.Count; ++i)
            {
                Array.Copy(fragments[i].Data, 0, buffer, (int)pos, (int)fragments[i].Length);
                VariableSizedBufferPool.Release(fragments[i].Data);

                pos += fragments[i].Length;
            }

            // All fragments of a message are of the same type, as set by the first fragment's opcode.
            this.Type = fragments[0].Type;

            // Reserver flags may be contained only in the first fragment

            this.Header = fragments[0].Header;
            this.Length = finalLength;
            this.Data   = buffer;
        }
Esempio n. 3
0
        /// <summary>
        /// This function will decode the received data incrementally with the associated websocket's extensions.
        /// </summary>
        public void DecodeWithExtensions(WebSocket webSocket)
        {
            if (webSocket.Extensions != null)
            {
                for (int i = 0; i < webSocket.Extensions.Length; ++i)
                {
                    var ext = webSocket.Extensions[i];
                    if (ext != null)
                    {
                        var newData = ext.Decode(this.Header, this.Data, (int)this.Length);
                        if (this.Data != newData)
                        {
                            VariableSizedBufferPool.Release(this.Data);
                            this.Data   = newData;
                            this.Length = (ulong)newData.Length;
                        }
                    }
                }
            }

            if (this.Type == WebSocketFrameTypes.Text && this.Data != null)
            {
                this.DataAsText = System.Text.Encoding.UTF8.GetString(this.Data, 0, (int)this.Length);
                VariableSizedBufferPool.Release(this.Data);
                this.Data = null;
            }
        }
        protected void FlushRemainingFragmentBuffer()
        {
            if (fragmentBuffer != null)
            {
                VariableSizedBufferPool.Resize(ref fragmentBuffer, fragmentBufferDataLength, false);

                AddStreamedFragment(fragmentBuffer);
                fragmentBuffer           = null;
                fragmentBufferDataLength = 0;
            }

#if !BESTHTTP_DISABLE_CACHING
            if (cacheStream != null)
            {
                cacheStream.Dispose();
                cacheStream = null;

                HTTPCacheService.SetBodyLength(baseRequest.CurrentUri, allFragmentSize);
            }
#endif
            var tmp = fragmentWaitEvent;
            fragmentWaitEvent = null;
            if (tmp != null)
            {
                (tmp as IDisposable).Dispose();
            }
        }
        public void Write(string str)
        {
            byte[] bytes = str.GetASCIIBytes();

            this.Write(bytes, 0, bytes.Length);
            VariableSizedBufferPool.Release(bytes);
        }
        protected byte[] DecodeStream(BufferPoolMemoryStream streamToDecode)
        {
            streamToDecode.Seek(0, SeekOrigin.Begin);

            // The cache stores the decoded data
            var encoding =
#if !BESTHTTP_DISABLE_CACHING
                IsFromCache ? null :
#endif
                GetHeaderValues("content-encoding");

#if !UNITY_WEBGL || UNITY_EDITOR
            Stream decoderStream = null;
#endif

            // Return early if there are no encoding used.
            if (encoding == null)
            {
                return(streamToDecode.ToArray());
            }
            else
            {
                switch (encoding[0])
                {
#if !UNITY_WEBGL || UNITY_EDITOR
                case "gzip": decoderStream = new Decompression.Zlib.GZipStream(streamToDecode, Decompression.Zlib.CompressionMode.Decompress); break;

                case "deflate": decoderStream = new Decompression.Zlib.DeflateStream(streamToDecode, Decompression.Zlib.CompressionMode.Decompress); break;
#endif
                //identity, utf-8, etc.
                default:
                    // Do not copy from one stream to an other, just return with the raw bytes
                    return(streamToDecode.ToArray());
                }
            }

#if !UNITY_WEBGL || UNITY_EDITOR
            using (var ms = new BufferPoolMemoryStream((int)streamToDecode.Length))
            {
                var buf       = VariableSizedBufferPool.Get(1024, true);
                int byteCount = 0;

                while ((byteCount = decoderStream.Read(buf, 0, buf.Length)) > 0)
                {
                    ms.Write(buf, 0, byteCount);
                }

                VariableSizedBufferPool.Release(buf);

                decoderStream.Dispose();
                return(ms.ToArray());
            }
#endif
        }
        private byte[] Decompress(byte[] data, int offset, int count, bool forceDecompress = false)
        {
            if (decompressorInputStream == null)
            {
                decompressorInputStream = new BufferPoolMemoryStream(count);
            }

            if (data != null)
            {
                decompressorInputStream.Write(data, offset, count);
            }

            if (!forceDecompress && decompressorInputStream.Length < MinLengthToDecompress)
            {
                return(null);
            }

            decompressorInputStream.Position = 0;

            if (decompressorGZipStream == null)
            {
                decompressorGZipStream = new Decompression.Zlib.GZipStream(decompressorInputStream,
                                                                           Decompression.Zlib.CompressionMode.Decompress,
                                                                           Decompression.Zlib.CompressionLevel.Default,
                                                                           true);
                decompressorGZipStream.FlushMode = Decompression.Zlib.FlushType.Sync;
            }

            if (decompressorOutputStream == null)
            {
                decompressorOutputStream = new BufferPoolMemoryStream();
            }
            decompressorOutputStream.SetLength(0);

            byte[] copyBuffer = VariableSizedBufferPool.Get(1024, true);

            int readCount;

            while ((readCount = decompressorGZipStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0)
            {
                decompressorOutputStream.Write(copyBuffer, 0, readCount);
            }

            VariableSizedBufferPool.Release(copyBuffer);

            decompressorGZipStream.SetLength(0);

            // TODO: be able to use a larger array
            byte[] result = decompressorOutputStream.ToArray();

            return(result);
        }
Esempio n. 8
0
        /// <summary>
        /// A function to decompress and return the data parameter with possible context takeover support (reusing the DeflateStream).
        /// </summary>
        private byte[] Decompress(byte[] data, int length)
        {
            if (decompressorInputStream == null)
            {
                decompressorInputStream = new BufferPoolMemoryStream(data.Length + 4);
            }

            decompressorInputStream.Write(data, 0, length);

            // http://tools.ietf.org/html/rfc7692#section-7.2.2
            // Append 4 octets of 0x00 0x00 0xff 0xff to the tail end of the payload of the message.
            decompressorInputStream.Write(PerMessageCompression.Trailer, 0, PerMessageCompression.Trailer.Length);

            decompressorInputStream.Position = 0;

            if (decompressorDeflateStream == null)
            {
                decompressorDeflateStream           = new DeflateStream(decompressorInputStream, CompressionMode.Decompress, CompressionLevel.Default, true, this.ServerMaxWindowBits);
                decompressorDeflateStream.FlushMode = FlushType.Sync;
            }

            if (decompressorOutputStream == null)
            {
                decompressorOutputStream = new BufferPoolMemoryStream();
            }
            decompressorOutputStream.SetLength(0);

            byte[] copyBuffer = VariableSizedBufferPool.Get(1024, true);
            int    readCount;

            while ((readCount = decompressorDeflateStream.Read(copyBuffer, 0, copyBuffer.Length)) != 0)
            {
                decompressorOutputStream.Write(copyBuffer, 0, readCount);
            }

            VariableSizedBufferPool.Release(copyBuffer);

            decompressorDeflateStream.SetLength(0);

            byte[] result = decompressorOutputStream.ToArray();

            if (this.ServerNoContextTakeover)
            {
                decompressorDeflateStream.Dispose();
                decompressorDeflateStream = null;
            }

            return(result);
        }
Esempio n. 9
0
        static void OnBufferCallback(int nativeId, IntPtr pBuffer, int length)
        {
            WebGLConnection conn = null;

            if (!Connections.TryGetValue(nativeId, out conn))
            {
                HTTPManager.Logger.Error("WebGLConnection - OnBufferCallback", "No WebGL connection found for nativeId: " + nativeId.ToString());
                return;
            }

            byte[] buffer = VariableSizedBufferPool.Get(length, true);

            // Copy data from the 'unmanaged' memory to managed memory. Buffer will be reclaimed by the GC.
            Marshal.Copy(pBuffer, buffer, 0, length);

            conn.OnBuffer(buffer, length);

            VariableSizedBufferPool.Release(buffer);
        }
        public WebSocketFrame(WebSocket webSocket, WebSocketFrameTypes type, byte[] data, UInt64 pos, UInt64 length, bool isFinal, bool useExtensions)
        {
            this.Type          = type;
            this.IsFinal       = isFinal;
            this.UseExtensions = useExtensions;

            this.DataLength = (int)length;
            if (data != null)
            {
                this.Data = VariableSizedBufferPool.Get(this.DataLength, true);
                Array.Copy(data, (int)pos, this.Data, 0, this.DataLength);
            }
            else
            {
                data = VariableSizedBufferPool.NoData;
            }

            // First byte: Final Bit + Rsv flags + OpCode
            byte finalBit = (byte)(IsFinal ? 0x80 : 0x0);

            this.Header = (byte)(finalBit | (byte)Type);

            if (this.UseExtensions && webSocket != null && webSocket.Extensions != null)
            {
                for (int i = 0; i < webSocket.Extensions.Length; ++i)
                {
                    var ext = webSocket.Extensions[i];
                    if (ext != null)
                    {
                        this.Header |= ext.GetFrameHeader(this, this.Header);
                        byte[] newData = ext.Encode(this);

                        if (newData != this.Data)
                        {
                            VariableSizedBufferPool.Release(this.Data);

                            this.Data       = newData;
                            this.DataLength = newData.Length;
                        }
                    }
                }
            }
        }
Esempio n. 11
0
        static void OnResponse(int nativeId, int httpStatus, IntPtr pBuffer, int length, int err)
        {
            HTTPManager.Logger.Information("WebGLConnection - OnResponse", string.Format("{0} {1} {2} {3}", nativeId, httpStatus, length, err));

            WebGLConnection conn = null;

            if (!Connections.TryGetValue(nativeId, out conn))
            {
                HTTPManager.Logger.Error("WebGLConnection - OnResponse", "No WebGL connection found for nativeId: " + nativeId.ToString());
                return;
            }

            byte[] buffer = VariableSizedBufferPool.Get(length, true);

            // Copy data from the 'unmanaged' memory to managed memory. Buffer will be reclaimed by the GC.
            Marshal.Copy(pBuffer, buffer, 0, length);

            conn.OnResponse(httpStatus, buffer, length);

            VariableSizedBufferPool.Release(buffer);
        }
Esempio n. 12
0
        /// <summary>
        /// It will send the given message to the server in one frame.
        /// </summary>
        public void Send(string message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("message must not be null!");
            }

            int count = System.Text.Encoding.UTF8.GetByteCount(message);

            byte[] data = VariableSizedBufferPool.Get(count, true);
            System.Text.Encoding.UTF8.GetBytes(message, 0, message.Length, data, 0);

            var frame = new WebSocketFrame(this.WebSocket, WebSocketFrameTypes.Text, data, 0, (ulong)count, true, true);

            if (frame.Data != null && frame.Data.Length > this.MaxFragmentSize)
            {
                WebSocketFrame[] additionalFrames = frame.Fragment(this.MaxFragmentSize);

                lock (SendLock)
                {
                    Send(frame);
                    if (additionalFrames != null)
                    {
                        for (int i = 0; i < additionalFrames.Length; ++i)
                        {
                            Send(additionalFrames[i]);
                        }
                    }
                }
            }
            else
            {
                Send(frame);
            }

            VariableSizedBufferPool.Release(data);
        }
Esempio n. 13
0
        /// <summary>
        /// Add data to the fragments list.
        /// </summary>
        /// <param name="buffer">The buffer to be added.</param>
        /// <param name="pos">The position where we start copy the data.</param>
        /// <param name="length">How many data we want to copy.</param>
        protected void FeedStreamFragment(byte[] buffer, int pos, int length)
        {
            if (buffer == null || length == 0)
            {
                return;
            }

            // If reading from cache, we don't want to read too much data to memory. So we will wait until the loaded fragment processed.
            WaitWhileFragmentQueueIsFull();

            if (fragmentBuffer == null)
            {
                fragmentBuffer           = VariableSizedBufferPool.Get(baseRequest.StreamFragmentSize, false);
                fragmentBufferDataLength = 0;
            }

            if (fragmentBufferDataLength + length <= baseRequest.StreamFragmentSize)
            {
                Array.Copy(buffer, pos, fragmentBuffer, fragmentBufferDataLength, length);
                fragmentBufferDataLength += length;

                if (fragmentBufferDataLength == baseRequest.StreamFragmentSize)
                {
                    AddStreamedFragment(fragmentBuffer);
                    fragmentBuffer           = null;
                    fragmentBufferDataLength = 0;
                }
            }
            else
            {
                int remaining = baseRequest.StreamFragmentSize - fragmentBufferDataLength;

                FeedStreamFragment(buffer, pos, remaining);
                FeedStreamFragment(buffer, pos + remaining, length - remaining);
            }
        }
Esempio n. 14
0
        internal override void Connect(Stream stream, HTTPRequest request)
        {
            bool isSecure = HTTPProtocolFactory.IsSecureProtocol(request.CurrentUri);

            if ((!this.IsTransparent || (isSecure && this.NonTransparentForHTTPS)))
            {
                using (var bufferedStream = new WriteOnlyBufferedStream(stream, HTTPRequest.UploadChunkSize))
                    using (var outStream = new BinaryWriter(bufferedStream, Encoding.UTF8))
                    {
                        bool retry;
                        do
                        {
                            // If we have to because of a authentication request, we will switch it to true
                            retry = false;

                            string connectStr = string.Format("CONNECT {0}:{1} HTTP/1.1", request.CurrentUri.Host, request.CurrentUri.Port.ToString());

                            HTTPManager.Logger.Information("HTTPConnection", "Sending " + connectStr);

                            outStream.SendAsASCII(connectStr);
                            outStream.Write(HTTPRequest.EOL);

                            outStream.SendAsASCII("Proxy-Connection: Keep-Alive");
                            outStream.Write(HTTPRequest.EOL);

                            outStream.SendAsASCII("Connection: Keep-Alive");
                            outStream.Write(HTTPRequest.EOL);

                            outStream.SendAsASCII(string.Format("Host: {0}:{1}", request.CurrentUri.Host, request.CurrentUri.Port.ToString()));
                            outStream.Write(HTTPRequest.EOL);

                            // Proxy Authentication
                            if (this.Credentials != null)
                            {
                                switch (this.Credentials.Type)
                                {
                                case AuthenticationTypes.Basic:
                                    // With Basic authentication we don't want to wait for a challenge, we will send the hash with the first request
                                    outStream.Write(string.Format("Proxy-Authorization: {0}", string.Concat("Basic ", Convert.ToBase64String(Encoding.UTF8.GetBytes(this.Credentials.UserName + ":" + this.Credentials.Password)))).GetASCIIBytes());
                                    outStream.Write(HTTPRequest.EOL);
                                    break;

                                case AuthenticationTypes.Unknown:
                                case AuthenticationTypes.Digest:
                                    var digest = DigestStore.Get(this.Address);
                                    if (digest != null)
                                    {
                                        string authentication = digest.GenerateResponseHeader(request, this.Credentials, true);
                                        if (!string.IsNullOrEmpty(authentication))
                                        {
                                            string auth = string.Format("Proxy-Authorization: {0}", authentication);
                                            if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
                                            {
                                                HTTPManager.Logger.Information("HTTPConnection", "Sending proxy authorization header: " + auth);
                                            }

                                            var bytes = auth.GetASCIIBytes();
                                            outStream.Write(bytes);
                                            outStream.Write(HTTPRequest.EOL);
                                            VariableSizedBufferPool.Release(bytes);
                                        }
                                    }

                                    break;
                                }
                            }

                            outStream.Write(HTTPRequest.EOL);

                            // Make sure to send all the wrote data to the wire
                            outStream.Flush();

                            request.ProxyResponse = new HTTPResponse(request, stream, false, false);

                            // Read back the response of the proxy
                            if (!request.ProxyResponse.Receive(-1, true))
                            {
                                throw new Exception("Connection to the Proxy Server failed!");
                            }

                            if (HTTPManager.Logger.Level <= Logger.Loglevels.Information)
                            {
                                HTTPManager.Logger.Information("HTTPConnection", "Proxy returned - status code: " + request.ProxyResponse.StatusCode + " message: " + request.ProxyResponse.Message + " Body: " + request.ProxyResponse.DataAsText);
                            }

                            switch (request.ProxyResponse.StatusCode)
                            {
                            // Proxy authentication required
                            // http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.8
                            case 407:
                            {
                                string authHeader = DigestStore.FindBest(request.ProxyResponse.GetHeaderValues("proxy-authenticate"));
                                if (!string.IsNullOrEmpty(authHeader))
                                {
                                    var digest = DigestStore.GetOrCreate(this.Address);
                                    digest.ParseChallange(authHeader);

                                    if (this.Credentials != null && digest.IsUriProtected(this.Address) && (!request.HasHeader("Proxy-Authorization") || digest.Stale))
                                    {
                                        retry = true;
                                    }
                                }

                                if (!retry)
                                {
                                    throw new Exception(string.Format("Can't authenticate Proxy! Status Code: \"{0}\", Message: \"{1}\" and Response: {2}", request.ProxyResponse.StatusCode, request.ProxyResponse.Message, request.ProxyResponse.DataAsText));
                                }
                                break;
                            }

                            default:
                                if (!request.ProxyResponse.IsSuccess)
                                {
                                    throw new Exception(string.Format("Proxy returned Status Code: \"{0}\", Message: \"{1}\" and Response: {2}", request.ProxyResponse.StatusCode, request.ProxyResponse.Message, request.ProxyResponse.DataAsText));
                                }
                                break;
                            }
                        } while (retry);
                    }// using outstream
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Internal function to send out received messages.
        /// </summary>
        void IProtocol.HandleEvents()
        {
            WebSocketFrameReader frame;

            while (CompletedFrames.TryDequeue(out frame))
            {
                // Bugs in the clients shouldn't interrupt the code, so we need to try-catch and ignore any exception occurring here
                try
                {
                    switch (frame.Type)
                    {
                    case WebSocketFrameTypes.Continuation:
                        if (OnIncompleteFrame != null)
                        {
                            OnIncompleteFrame(this, frame);
                        }
                        break;

                    case WebSocketFrameTypes.Text:
                        // Any not Final frame is handled as a fragment
                        if (!frame.IsFinal)
                        {
                            goto case WebSocketFrameTypes.Continuation;
                        }

                        if (OnText != null)
                        {
                            OnText(this, frame.DataAsText);
                        }
                        break;

                    case WebSocketFrameTypes.Binary:
                        // Any not Final frame is handled as a fragment
                        if (!frame.IsFinal)
                        {
                            goto case WebSocketFrameTypes.Continuation;
                        }

                        if (OnBinary != null)
                        {
                            OnBinary(this, frame.Data);
                        }
                        break;
                    }
                }
                catch (Exception ex)
                {
                    HTTPManager.Logger.Exception("WebSocketResponse", "HandleEvents", ex);
                }
            }

            // 2015.05.09
            // State checking added because if there is an error the OnClose called first, and then the OnError.
            // Now, when there is an error only the OnError event will be called!
            if (IsClosed && OnClosed != null && baseRequest.State == HTTPRequestStates.Processing)
            {
                try
                {
                    UInt16 statusCode = 0;
                    string msg        = string.Empty;

                    // If we received any data, we will get the status code and the message from it
                    if (/*CloseFrame != null && */ CloseFrame.Data != null && CloseFrame.Data.Length >= 2)
                    {
                        if (BitConverter.IsLittleEndian)
                        {
                            Array.Reverse(CloseFrame.Data, 0, 2);
                        }
                        statusCode = BitConverter.ToUInt16(CloseFrame.Data, 0);

                        if (CloseFrame.Data.Length > 2)
                        {
                            msg = Encoding.UTF8.GetString(CloseFrame.Data, 2, CloseFrame.Data.Length - 2);
                        }

                        VariableSizedBufferPool.Release(CloseFrame.Data);
                    }

                    OnClosed(this, statusCode, msg);
                }
                catch (Exception ex)
                {
                    HTTPManager.Logger.Exception("WebSocketResponse", "HandleEvents - OnClosed", ex);
                }
            }
        }
Esempio n. 16
0
        internal void Read(Stream stream)
        {
            // For the complete documentation for this section see:
            // http://tools.ietf.org/html/rfc6455#section-5.2

            this.Header = ReadByte(stream);

            // The first byte is the Final Bit and the type of the frame
            IsFinal = (this.Header & 0x80) != 0;
            Type    = (WebSocketFrameTypes)(this.Header & 0xF);

            byte maskAndLength = ReadByte(stream);

            // The second byte is the Mask Bit and the length of the payload data
            HasMask = (maskAndLength & 0x80) != 0;

            // if 0-125, that is the payload length.
            Length = (UInt64)(maskAndLength & 127);

            // If 126, the following 2 bytes interpreted as a 16-bit unsigned integer are the payload length.
            if (Length == 126)
            {
                byte[] rawLen = VariableSizedBufferPool.Get(2, true);

                stream.ReadBuffer(rawLen, 2);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(rawLen, 0, 2);
                }

                Length = (UInt64)BitConverter.ToUInt16(rawLen, 0);

                VariableSizedBufferPool.Release(rawLen);
            }
            else if (Length == 127)
            {
                // If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
                // most significant bit MUST be 0) are the payload length.

                byte[] rawLen = VariableSizedBufferPool.Get(8, true);

                stream.ReadBuffer(rawLen, 8);

                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(rawLen, 0, 8);
                }

                Length = (UInt64)BitConverter.ToUInt64(rawLen, 0);

                VariableSizedBufferPool.Release(rawLen);
            }

            // The sent byte array as a mask to decode the data.
            byte[] mask = null;

            // Read the Mask, if has any
            if (HasMask)
            {
                mask = VariableSizedBufferPool.Get(4, true);
                if (stream.Read(mask, 0, 4) < mask.Length)
                {
                    throw ExceptionHelper.ServerClosedTCPStream();
                }
            }

            if (Type == WebSocketFrameTypes.Text || Type == WebSocketFrameTypes.Continuation)
            {
                Data = VariableSizedBufferPool.Get((long)Length, true);
            }
            else
            if (Length == 0)
            {
                Data = VariableSizedBufferPool.NoData;
            }
            else
            {
                Data = new byte[Length];
            }
            //Data = Type == WebSocketFrameTypes.Text ? VariableSizedBufferPool.Get((long)Length, true) : new byte[Length];

            if (Length == 0L)
            {
                return;
            }

            uint readLength = 0;

            do
            {
                int read = stream.Read(Data, (int)readLength, (int)(Length - readLength));

                if (read <= 0)
                {
                    throw ExceptionHelper.ServerClosedTCPStream();
                }

                readLength += (uint)read;
            } while (readLength < Length);

            if (HasMask)
            {
                for (uint i = 0; i < Length; ++i)
                {
                    Data[i] = (byte)(Data[i] ^ mask[i % 4]);
                }

                VariableSizedBufferPool.Release(mask);
            }
        }
Esempio n. 17
0
        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
        protected void ReadChunked(Stream stream)
        {
            BeginReceiveStreamFragments();

            string contentLengthHeader    = GetFirstHeaderValue("Content-Length");
            bool   hasContentLengthHeader = !string.IsNullOrEmpty(contentLengthHeader);
            int    realLength             = 0;

            if (hasContentLengthHeader)
            {
                hasContentLengthHeader = int.TryParse(contentLengthHeader, out realLength);
            }

            if (HTTPManager.Logger.Level == Logger.Loglevels.All)
            {
                VerboseLogging(string.Format("ReadChunked - hasContentLengthHeader: {0}, contentLengthHeader: {1} realLength: {2:N0}", hasContentLengthHeader.ToString(), contentLengthHeader, realLength));
            }

            using (var output = new BufferPoolMemoryStream())
            {
                int chunkLength = ReadChunkLength(stream);

                if (HTTPManager.Logger.Level == Logger.Loglevels.All)
                {
                    VerboseLogging(string.Format("chunkLength: {0:N0}", chunkLength));
                }

                byte[] buffer = VariableSizedBufferPool.Get(Mathf.NextPowerOfTwo(chunkLength), true);

                int contentLength = 0;

                // Progress report:
                baseRequest.DownloadLength          = hasContentLengthHeader ? realLength : chunkLength;
                baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                      || this.IsFromCache
#endif
                ;

                string encoding =
#if !BESTHTTP_DISABLE_CACHING
                    IsFromCache ? null :
#endif
                    GetFirstHeaderValue("content-encoding");
                bool gzipped = !string.IsNullOrEmpty(encoding) && encoding == "gzip";

                while (chunkLength != 0)
                {
                    // To avoid more GC garbage we use only one buffer, and resize only if the next chunk doesn't fit.
                    if (buffer.Length < chunkLength)
                    {
                        VariableSizedBufferPool.Resize(ref buffer, chunkLength, true);
                    }

                    int readBytes = 0;

                    // Fill up the buffer
                    do
                    {
                        int bytes = stream.Read(buffer, readBytes, chunkLength - readBytes);
                        if (bytes <= 0)
                        {
                            throw ExceptionHelper.ServerClosedTCPStream();
                        }

                        readBytes += bytes;

                        // Progress report:
                        // Placing reporting inside this cycle will report progress much more frequent
                        baseRequest.Downloaded += bytes;
                        baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                              || this.IsFromCache
#endif
                        ;
                    } while (readBytes < chunkLength);

                    if (baseRequest.UseStreaming)
                    {
                        if (gzipped)
                        {
                            var decompressed = Decompress(buffer, 0, readBytes);
                            if (decompressed != null)
                            {
                                FeedStreamFragment(decompressed, 0, decompressed.Length);
                            }
                        }
                        else
                        {
                            FeedStreamFragment(buffer, 0, readBytes);
                        }
                    }
                    else
                    {
                        output.Write(buffer, 0, readBytes);
                    }

                    // Every chunk data has a trailing CRLF
                    ReadTo(stream, LF);

                    contentLength += readBytes;

                    // read the next chunk's length
                    chunkLength = ReadChunkLength(stream);

                    if (HTTPManager.Logger.Level == Logger.Loglevels.All)
                    {
                        VerboseLogging(string.Format("chunkLength: {0:N0}", chunkLength));
                    }

                    if (!hasContentLengthHeader)
                    {
                        baseRequest.DownloadLength += chunkLength;
                    }
                    baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                          || this.IsFromCache
#endif
                    ;
                }

                VariableSizedBufferPool.Release(buffer);

                if (baseRequest.UseStreaming)
                {
                    if (gzipped)
                    {
                        var decompressed = Decompress(null, 0, 0, true);
                        if (decompressed != null)
                        {
                            FeedStreamFragment(decompressed, 0, decompressed.Length);
                        }
                    }

                    FlushRemainingFragmentBuffer();
                }

                // Read the trailing headers or the CRLF
                ReadHeaders(stream);

                // HTTP servers sometimes use compression (gzip) or deflate methods to optimize transmission.
                // How both chunked and gzip encoding interact is dictated by the two-staged encoding of HTTP:
                //  first the content stream is encoded as (Content-Encoding: gzip), after which the resulting byte stream is encoded for transfer using another encoder (Transfer-Encoding: chunked).
                //  This means that in case both compression and chunked encoding are enabled, the chunk encoding itself is not compressed, and the data in each chunk should not be compressed individually.
                //  The remote endpoint can decode the incoming stream by first decoding it with the Transfer-Encoding, followed by the specified Content-Encoding.
                // It would be a better implementation when the chunk would be decododed on-the-fly. Becouse now the whole stream must be downloaded, and then decoded. It needs more memory.
                if (!baseRequest.UseStreaming)
                {
                    this.Data = DecodeStream(output);
                }
            }

            CloseDecompressors();
        }
Esempio n. 18
0
        private void SendThreadFunc()
        {
            try
            {
                using (WriteOnlyBufferedStream bufferedStream = new WriteOnlyBufferedStream(this.Stream, 16 * 1024))
                {
                    while (!closed && !closeSent)
                    {
                        //if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
                        //    HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Waiting...");
                        newFrameSignal.WaitOne();

                        try
                        {
                            //if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
                            //    HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Wait is over, " + localFrames.Count.ToString() + " new frames!");

                            WebSocketFrame frame;
                            while (this.unsentFrames.TryDequeue(out frame))
                            {
                                if (!closeSent)
                                {
                                    using (var rawData = frame.Get())
                                        Stream.Write(rawData.Data, 0, rawData.Length);

                                    VariableSizedBufferPool.Release(frame.Data);

                                    if (frame.Type == WebSocketFrameTypes.ConnectionClose)
                                    {
                                        closeSent = true;
                                    }
                                }

                                Interlocked.Add(ref this._bufferedAmount, -frame.DataLength);
                            }

                            Stream.Flush();
                        }
                        catch (Exception ex)
                        {
                            if (HTTPUpdateDelegator.IsCreated)
                            {
                                this.baseRequest.Exception = ex;
                                this.baseRequest.State     = HTTPRequestStates.Error;
                            }
                            else
                            {
                                this.baseRequest.State = HTTPRequestStates.Aborted;
                            }

                            closed = true;
                        }
                    }
                }
            }
            finally
            {
                sendThreadCreated = false;
                (newFrameSignal as IDisposable).Dispose();
                newFrameSignal = null;

                HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Closed!");
            }
        }
Esempio n. 19
0
        // No transfer-encoding just raw bytes.
        internal void ReadRaw(Stream stream, long contentLength)
        {
            BeginReceiveStreamFragments();

            // Progress report:
            baseRequest.DownloadLength          = contentLength;
            baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                  || this.IsFromCache
#endif
            ;

            if (HTTPManager.Logger.Level == Logger.Loglevels.All)
            {
                VerboseLogging(string.Format("ReadRaw - contentLength: {0:N0}", contentLength));
            }

            string encoding =
#if !BESTHTTP_DISABLE_CACHING
                IsFromCache ? null :
#endif
                GetFirstHeaderValue("content-encoding");
            bool gzipped = !string.IsNullOrEmpty(encoding) && encoding == "gzip";
            if (!baseRequest.UseStreaming && contentLength > 2147483646)
            {
                throw new OverflowException("You have to use STREAMING to download files bigger than 2GB!");
            }

            using (var output = new BufferPoolMemoryStream(baseRequest.UseStreaming ? 0 : (int)contentLength))
            {
                byte[] buffer    = VariableSizedBufferPool.Get(Math.Max(baseRequest.StreamFragmentSize, MinBufferSize), true);
                int    readBytes = 0;

                while (contentLength > 0)
                {
                    readBytes = 0;

                    do
                    {
                        int readbuffer = (int)Math.Min(2147483646, (uint)contentLength);
                        int bytes      = stream.Read(buffer, readBytes, Math.Min(readbuffer, buffer.Length - readBytes));

                        if (bytes <= 0)
                        {
                            throw ExceptionHelper.ServerClosedTCPStream();
                        }

                        readBytes     += bytes;
                        contentLength -= bytes;

                        // Progress report:
                        baseRequest.Downloaded += bytes;
                        baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                              || this.IsFromCache
#endif
                        ;
                    } while (readBytes < buffer.Length && contentLength > 0);

                    if (baseRequest.UseStreaming)
                    {
                        if (gzipped)
                        {
                            var decompressed = Decompress(buffer, 0, readBytes);
                            if (decompressed != null)
                            {
                                FeedStreamFragment(decompressed, 0, decompressed.Length);
                            }
                        }
                        else
                        {
                            FeedStreamFragment(buffer, 0, readBytes);
                        }
                    }
                    else
                    {
                        output.Write(buffer, 0, readBytes);
                    }
                }
                ;

                VariableSizedBufferPool.Release(buffer);

                if (baseRequest.UseStreaming)
                {
                    if (gzipped)
                    {
                        var decompressed = Decompress(null, 0, 0, true);
                        if (decompressed != null)
                        {
                            FeedStreamFragment(decompressed, 0, decompressed.Length);
                        }
                    }

                    FlushRemainingFragmentBuffer();
                }

                if (!baseRequest.UseStreaming)
                {
                    this.Data = DecodeStream(output);
                }
            }

            CloseDecompressors();
        }
Esempio n. 20
0
        protected void ReadUnknownSize(Stream stream)
        {
            string encoding =
#if !BESTHTTP_DISABLE_CACHING
                IsFromCache ? null :
#endif
                GetFirstHeaderValue("content-encoding");
            bool gzipped = !string.IsNullOrEmpty(encoding) && encoding == "gzip";

            using (var output = new BufferPoolMemoryStream())
            {
                byte[] buffer = VariableSizedBufferPool.Get(Math.Max(baseRequest.StreamFragmentSize, MinBufferSize), false);

                if (HTTPManager.Logger.Level == Logger.Loglevels.All)
                {
                    VerboseLogging(string.Format("ReadUnknownSize - buffer size: {0:N0}", buffer.Length));
                }

                int readBytes = 0;
                int bytes     = 0;
                do
                {
                    readBytes = 0;

                    do
                    {
                        bytes = 0;

#if !NETFX_CORE || UNITY_EDITOR
                        NetworkStream networkStream = stream as NetworkStream;
                        // If we have the good-old NetworkStream, than we can use the DataAvailable property. On WP8 platforms, these are omitted... :/
                        if (networkStream != null && baseRequest.EnableSafeReadOnUnknownContentLength)
                        {
                            for (int i = readBytes; i < buffer.Length && networkStream.DataAvailable; ++i)
                            {
                                int read = stream.ReadByte();
                                if (read >= 0)
                                {
                                    buffer[i] = (byte)read;
                                    bytes++;
                                }
                                else
                                {
                                    break;
                                }
                            }
                        }
                        else // This will be good anyway, but a little slower.
#endif
                        {
                            bytes = stream.Read(buffer, readBytes, buffer.Length - readBytes);
                        }

                        readBytes += bytes;

                        // Progress report:
                        baseRequest.Downloaded             += bytes;
                        baseRequest.DownloadLength          = baseRequest.Downloaded;
                        baseRequest.DownloadProgressChanged = this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                              || this.IsFromCache
#endif
                        ;
                    } while (readBytes < buffer.Length && bytes > 0);

                    if (baseRequest.UseStreaming)
                    {
                        if (gzipped)
                        {
                            var decompressed = Decompress(buffer, 0, readBytes);
                            if (decompressed != null)
                            {
                                FeedStreamFragment(decompressed, 0, decompressed.Length);
                            }
                        }
                        else
                        {
                            FeedStreamFragment(buffer, 0, readBytes);
                        }
                    }
                    else
                    {
                        output.Write(buffer, 0, readBytes);
                    }
                } while (bytes > 0);

                VariableSizedBufferPool.Release(buffer);

                if (baseRequest.UseStreaming)
                {
                    if (gzipped)
                    {
                        var decompressed = Decompress(null, 0, 0, true);
                        if (decompressed != null)
                        {
                            FeedStreamFragment(decompressed, 0, decompressed.Length);
                        }
                    }

                    FlushRemainingFragmentBuffer();
                }

                if (!baseRequest.UseStreaming)
                {
                    this.Data = DecodeStream(output);
                }
            }

            CloseDecompressors();
        }
        private void SendThreadFunc(object param)
        {
            List <WebSocketFrame> localFrames = new List <WebSocketFrame>();

            try
            {
                while (!closed && !closeSent)
                {
                    //if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
                    //    HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Waiting...");
                    newFrameSignal.WaitOne();

                    try
                    {
                        lock (SendLock)
                        {
                            // add frames int reversed order
                            for (int i = this.unsentFrames.Count - 1; i >= 0; --i)
                            {
                                localFrames.Add(this.unsentFrames[i]);
                            }

                            this.unsentFrames.Clear();
                        }

                        //if (HTTPManager.Logger.Level <= Logger.Loglevels.All)
                        //    HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Wait is over, " + localFrames.Count.ToString() + " new frames!");

                        while (localFrames.Count > 0)
                        {
                            WebSocketFrame frame = localFrames[localFrames.Count - 1];
                            localFrames.RemoveAt(localFrames.Count - 1);

                            if (!closeSent)
                            {
                                using (var rawData = frame.Get())
                                {
                                    Stream.Write(rawData.Data, 0, rawData.Length);
                                }

                                //if (frame.Type == WebSocketFrameTypes.Text)
                                VariableSizedBufferPool.Release(frame.Data);

                                if (frame.Type == WebSocketFrameTypes.ConnectionClose)
                                {
                                    closeSent = true;
                                }
                            }

                            Interlocked.Add(ref this._bufferedAmount, -frame.DataLength);
                        }

                        Stream.Flush();
                    }
                    catch (Exception ex)
                    {
                        if (HTTPUpdateDelegator.IsCreated)
                        {
                            this.baseRequest.Exception = ex;
                            this.baseRequest.State     = HTTPRequestStates.Error;
                        }
                        else
                        {
                            this.baseRequest.State = HTTPRequestStates.Aborted;
                        }

                        closed = true;
                    }
                }
            }
            finally
            {
                sendThreadCreated = false;
                (newFrameSignal as IDisposable).Dispose();
                newFrameSignal = null;

                HTTPManager.Logger.Information("WebSocketResponse", "SendThread - Closed!");
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Update function that should be called regularly from a Unity event(Update, LateUpdate). Callbacks are dispatched from this function.
        /// </summary>
        public static void OnUpdate()
        {
            // We will try to acquire a lock. If it fails, we will skip this frame without calling any callback.
            if (System.Threading.Monitor.TryEnter(Locker))
            {
                try
                {
                    IsCallingCallbacks = true;
                    try
                    {
                        for (int i = 0; i < ActiveConnections.Count; ++i)
                        {
                            ConnectionBase conn = ActiveConnections[i];

                            switch (conn.State)
                            {
                            case HTTPConnectionStates.Processing:
                                conn.HandleProgressCallback();

                                if (conn.CurrentRequest.UseStreaming && conn.CurrentRequest.Response != null && conn.CurrentRequest.Response.HasStreamedFragments())
                                {
                                    conn.HandleCallback();
                                }

                                try
                                {
                                    if (((!conn.CurrentRequest.UseStreaming && conn.CurrentRequest.UploadStream == null) || conn.CurrentRequest.EnableTimoutForStreaming) &&
                                        DateTime.UtcNow - conn.StartTime > conn.CurrentRequest.Timeout)
                                    {
                                        conn.Abort(HTTPConnectionStates.TimedOut);
                                    }
                                }
                                catch (OverflowException)
                                {
                                    HTTPManager.Logger.Warning("HTTPManager", "TimeSpan overflow");
                                }
                                break;

                            case HTTPConnectionStates.TimedOut:
                                // The connection is still in TimedOut state, and if we waited enough time, we will dispatch the
                                //  callback and recycle the connection
                                try
                                {
                                    if (DateTime.UtcNow - conn.TimedOutStart > TimeSpan.FromMilliseconds(500))
                                    {
                                        HTTPManager.Logger.Information("HTTPManager", "Hard aborting connection because of a long waiting TimedOut state");

                                        conn.CurrentRequest.Response = null;
                                        conn.CurrentRequest.State    = HTTPRequestStates.TimedOut;
                                        conn.HandleCallback();

                                        // this will set the connection's CurrentRequest to null
                                        RecycleConnection(conn);
                                    }
                                }
                                catch (OverflowException)
                                {
                                    HTTPManager.Logger.Warning("HTTPManager", "TimeSpan overflow");
                                }
                                break;

                            case HTTPConnectionStates.Redirected:
                                // If the server redirected us, we need to find or create a connection to the new server and send out the request again.
                                SendRequest(conn.CurrentRequest);

                                RecycleConnection(conn);
                                break;

                            case HTTPConnectionStates.WaitForRecycle:
                                // If it's a streamed request, it's finished now
                                conn.CurrentRequest.FinishStreaming();

                                // Call the callback
                                conn.HandleCallback();

                                // Then recycle the connection
                                RecycleConnection(conn);
                                break;

                            case HTTPConnectionStates.Upgraded:
                                // The connection upgraded to an other protocol
                                conn.HandleCallback();
                                break;

                            case HTTPConnectionStates.WaitForProtocolShutdown:
                                var ws = conn.CurrentRequest.Response as IProtocol;
                                if (ws != null)
                                {
                                    ws.HandleEvents();
                                }

                                if (ws == null || ws.IsClosed)
                                {
                                    conn.HandleCallback();

                                    // After both sending and receiving a Close message, an endpoint considers the WebSocket connection closed and MUST close the underlying TCP connection.
                                    conn.Dispose();
                                    RecycleConnection(conn);
                                }
                                break;

                            case HTTPConnectionStates.AbortRequested:
                                // Corner case: we aborted a WebSocket connection
                            {
                                ws = conn.CurrentRequest.Response as IProtocol;
                                if (ws != null)
                                {
                                    ws.HandleEvents();

                                    if (ws.IsClosed)
                                    {
                                        conn.HandleCallback();
                                        conn.Dispose();

                                        RecycleConnection(conn);
                                    }
                                }
                            }

                                if (conn.CurrentRequest != null)
                                {
                                    // Still process any callbacks.
                                    goto case HTTPConnectionStates.Processing;
                                }
                                else
                                {
                                    break;
                                }

                            case HTTPConnectionStates.Closed:
                                // If it's a streamed request, it's finished now
                                conn.CurrentRequest.FinishStreaming();

                                // Call the callback
                                conn.HandleCallback();

                                // It will remove from the ActiveConnections
                                RecycleConnection(conn);
                                break;

                            case HTTPConnectionStates.Free:
                                RecycleConnection(conn);
                                break;
                            }
                        }
                    }
                    finally
                    {
                        IsCallingCallbacks = false;
                    }

                    // Just try to grab the lock, if we can't have it we can wait another turn because it isn't
                    //  critical to do it right now.
                    if (System.Threading.Monitor.TryEnter(RecycledConnections))
                    {
                        try
                        {
                            if (RecycledConnections.Count > 0)
                            {
                                for (int i = 0; i < RecycledConnections.Count; ++i)
                                {
                                    var connection = RecycledConnections[i];
                                    // If in a callback made a request that acquired this connection, then we will not remove it from the
                                    //  active connections.
                                    if (connection.IsFree)
                                    {
                                        ActiveConnections.Remove(connection);
                                        FreeConnections.Add(connection);
                                    }
                                }
                                RecycledConnections.Clear();
                            }
                        }
                        finally
                        {
                            System.Threading.Monitor.Exit(RecycledConnections);
                        }
                    }

                    if (FreeConnections.Count > 0)
                    {
                        for (int i = 0; i < FreeConnections.Count; i++)
                        {
                            var connection = FreeConnections[i];

                            if (connection.IsRemovable)
                            {
                                // Remove the connection from the connection reference table
                                List <ConnectionBase> connections = null;
                                if (Connections.TryGetValue(connection.ServerAddress, out connections))
                                {
                                    connections.Remove(connection);
                                }

                                // Dispose the connection
                                connection.Dispose();

                                FreeConnections.RemoveAt(i);
                                i--;
                            }
                        }
                    }


                    if (CanProcessFromQueue())
                    {
                        // Sort the queue by priority, only if we have to
                        if (RequestQueue.Find((req) => req.Priority != 0) != null)
                        {
                            RequestQueue.Sort((req1, req2) => req1.Priority - req2.Priority);
                        }

                        // Create an array from the queue and clear it. When we call the SendRequest while still no room for new connections, the same queue will be rebuilt.

                        var queue = RequestQueue.ToArray();
                        RequestQueue.Clear();

                        for (int i = 0; i < queue.Length; ++i)
                        {
                            SendRequest(queue[i]);
                        }
                    }
                }
                finally
                {
                    System.Threading.Monitor.Exit(Locker);
                }
            }

            if (heartbeats != null)
            {
                heartbeats.Update();
            }

            VariableSizedBufferPool.Maintain();
        }
 public void Dispose()
 {
     VariableSizedBufferPool.Release(Data);
     Data = null;
 }