Пример #1
0
        public RawFrameData Get()
        {
            if (Data == null)
            {
                Data = VariableSizedBufferPool.NoData;
            }

            using (var ms = new BufferPoolMemoryStream(this.DataLength + 9))
            {
                // For the complete documentation for this section see:
                // http://tools.ietf.org/html/rfc6455#section-5.2

                // Write the header
                ms.WriteByte(this.Header);

                // The length of the "Payload data", in bytes: if 0-125, that is the payload length.  If 126, the following 2 bytes interpreted as a
                // 16-bit unsigned integer are the payload length.  If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
                // most significant bit MUST be 0) are the payload length.  Multibyte length quantities are expressed in network byte order.
                if (this.DataLength < 126)
                {
                    ms.WriteByte((byte)(0x80 | (byte)this.DataLength));
                }
                else if (this.DataLength < UInt16.MaxValue)
                {
                    ms.WriteByte((byte)(0x80 | 126));
                    byte[] len = BitConverter.GetBytes((UInt16)this.DataLength);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(len, 0, len.Length);
                    }

                    ms.Write(len, 0, len.Length);
                }
                else
                {
                    ms.WriteByte((byte)(0x80 | 127));
                    byte[] len = BitConverter.GetBytes((UInt64)this.DataLength);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(len, 0, len.Length);
                    }

                    ms.Write(len, 0, len.Length);
                }

                // All frames sent from the client to the server are masked by a 32-bit value that is contained within the frame.  This field is
                // present if the mask bit is set to 1 and is absent if the mask bit is set to 0.
                // If the data is being sent by the client, the frame(s) MUST be masked.
                byte[] mask = BitConverter.GetBytes((Int32)this.GetHashCode());
                ms.Write(mask, 0, mask.Length);

                // Do the masking.
                for (int i = 0; i < this.DataLength; ++i)
                {
                    ms.WriteByte((byte)(Data[i] ^ mask[i % 4]));
                }

                return(new RawFrameData(ms.ToArray(true), (int)ms.Length));
            }
        }
 void OnBuffer(byte[] buffer, int bufferLength)
 {
     if (Stream != null)
     {
         Stream.Write(buffer, 0, bufferLength);
         Stream.Write(HTTPRequest.EOL, 0, HTTPRequest.EOL.Length);
     }
 }
Пример #3
0
 void OnBuffer(byte[] buffer, int bufferLength)
 {
     if (Stream != null)
     {
         Stream.Write(buffer, 0, bufferLength);
         //Stream.Write(new byte[2] { HTTPResponse.CR, HTTPResponse.LF }, 0, 2);
         Stream.Write(HTTPRequest.EOL, 0, HTTPRequest.EOL.Length);
     }
 }
Пример #4
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(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 = BufferPool.Get(1024, true);
            int    readCount;

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

            BufferPool.Release(copyBuffer);

            decompressorDeflateStream.SetLength(0);

            byte[] result = decompressorOutputStream.ToArray();

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

            return(result);
        }
Пример #5
0
        internal void AddData(Stream stream)
        {
            if (this.IsCompressed)
            {
                using (var decoderStream = new Decompression.Zlib.GZipStream(stream, Decompression.Zlib.CompressionMode.Decompress))
                {
                    using (var ms = new BufferPoolMemoryStream((int)stream.Length))
                    {
                        var buf       = BufferPool.Get(8 * 1024, true);
                        int byteCount = 0;

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

                        BufferPool.Release(buf);

                        base.Data = ms.ToArray();
                    }
                }
            }
            else
            {
                base.Data = BufferPool.Get(stream.Length, false);
                stream.Read(base.Data, 0, (int)stream.Length);
            }
        }
Пример #6
0
		public virtual void Add(WriteBatch writeBatch, string key, byte[] value, ushort? expectedVersion = null)
		{
		    var stream = new BufferPoolMemoryStream(BufferPool);
            stream.Write(value, 0, value.Length);
		    stream.Position = 0;

			writeBatch.Add(key, stream, TableName, expectedVersion);
		}
Пример #7
0
        public virtual void Add(WriteBatch writeBatch, Slice key, byte[] value, ushort?expectedVersion = null)
        {
            var stream = new BufferPoolMemoryStream();

            stream.Write(value, 0, value.Length);
            stream.Position = 0;

            writeBatch.Add(key, stream, TableName, expectedVersion);
        }
Пример #8
0
        public DecompressedData Decompress(byte[] data, int offset, int count, bool forceDecompress = false, bool dataCanBeLarger = false)
        {
            if (decompressorInputStream == null)
            {
                decompressorInputStream = new BufferPoolMemoryStream(count);
            }

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

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

            decompressorInputStream.Position = 0;

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

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

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

            int readCount;
            int sumReadCount = 0;

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

            BufferPool.Release(copyBuffer);

            // If no read is done (returned with any data) don't zero out the input stream, as it would delete any not yet used data.
            if (sumReadCount > 0)
            {
                decompressorGZipStream.SetLength(0);
            }

            byte[] result = decompressorOutputStream.ToArray(dataCanBeLarger);

            return(new DecompressedData(result, dataCanBeLarger ? (int)decompressorOutputStream.Length : result.Length));
        }
Пример #9
0
        public override byte[] GetData()
        {
            if (CachedData != null)
            {
                return(CachedData);
            }

            using (var ms = new BufferPoolMemoryStream())
            {
                for (int i = 0; i < Fields.Count; ++i)
                {
                    HTTPFieldData field = Fields[i];

                    // Set the boundary
                    ms.WriteLine("--" + Boundary);

                    // Set up Content-Disposition header to our form with the name
                    ms.WriteLine("Content-Disposition: form-data; name=\"" + field.Name + "\"" + (!string.IsNullOrEmpty(field.FileName) ? "; filename=\"" + field.FileName + "\"" : string.Empty));

                    // Set up Content-Type head for the form.
                    if (!string.IsNullOrEmpty(field.MimeType))
                    {
                        ms.WriteLine("Content-Type: " + field.MimeType);
                    }

                    ms.WriteLine("Content-Length: " + field.Payload.Length.ToString());
                    ms.WriteLine();

                    // Write the actual data to the MemoryStream
                    ms.Write(field.Payload, 0, field.Payload.Length);

                    ms.Write(HTTPRequest.EOL, 0, HTTPRequest.EOL.Length);
                }

                // Write out the trailing boundary
                ms.WriteLine("--" + Boundary + "--");

                IsChanged = false;

                // Set the RawData of our request
                return(CachedData = ms.ToArray());
            }
        }
Пример #10
0
        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       = BufferPool.Get(1024, true);
                int byteCount = 0;

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

                BufferPool.Release(buf);

                decoderStream.Dispose();
                return(ms.ToArray());
            }
#endif
        }
Пример #11
0
        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);
        }
Пример #12
0
        public static byte[] EncodeCloseData(UInt16 code, string message)
        {
            //If there is a body, the first two bytes of the body MUST be a 2-byte unsigned integer
            // (in network byte order) representing a status code with value /code/ defined in Section 7.4 (http://tools.ietf.org/html/rfc6455#section-7.4). Following the 2-byte integer,
            // the body MAY contain UTF-8-encoded data with value /reason/, the interpretation of which is not defined by this specification.
            // This data is not necessarily human readable but may be useful for debugging or passing information relevant to the script that opened the connection.
            int msgLen = Encoding.UTF8.GetByteCount(message);

            using (var ms = new BufferPoolMemoryStream(2 + msgLen))
            {
                byte[] buff = BitConverter.GetBytes(code);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(buff, 0, buff.Length);
                }

                ms.Write(buff, 0, buff.Length);

                buff = Encoding.UTF8.GetBytes(message);
                ms.Write(buff, 0, buff.Length);

                return(ms.ToArray());
            }
        }
Пример #13
0
        public void AddField(string fieldName, string value, System.Text.Encoding encoding)
        {
            var enc       = encoding ?? System.Text.Encoding.UTF8;
            var byteCount = enc.GetByteCount(value);
            var buffer    = BufferPool.Get(byteCount, true);
            var stream    = new BufferPoolMemoryStream();

            enc.GetBytes(value, 0, value.Length, buffer, 0);

            stream.Write(buffer, 0, byteCount);

            stream.Position = 0;

            string mime = encoding != null ? "text/plain; charset=" + encoding.WebName : null;

            AddStreamField(stream, fieldName, null, mime);
        }
Пример #14
0
        public void AddStreamField(System.IO.Stream stream, string fieldName, string fileName, string mimeType)
        {
            var header = new BufferPoolMemoryStream();

            header.WriteLine("--" + this.boundary);
            header.WriteLine("Content-Disposition: form-data; name=\"" + fieldName + "\"" + (!string.IsNullOrEmpty(fileName) ? "; filename=\"" + fileName + "\"" : string.Empty));
            // Set up Content-Type head for the form.
            if (!string.IsNullOrEmpty(mimeType))
            {
                header.WriteLine("Content-Type: " + mimeType);
            }
            header.WriteLine("Content-Length: " + stream.Length.ToString());
            header.WriteLine();
            header.Position = 0;

            var footer = new BufferPoolMemoryStream();

            footer.Write(HTTPRequest.EOL, 0, HTTPRequest.EOL.Length);
            footer.Position = 0;

            // all wrapped streams going to be disposed by the StreamList wrapper.
            var wrapper = new StreamList(header, stream, footer);

            try
            {
                if (this._length >= 0)
                {
                    this._length += wrapper.Length;
                }
            }
            catch
            {
                this._length = -1;
            }

            this.fields.Enqueue(wrapper);
        }
Пример #15
0
        protected override void ThreadFunc()
        {
            // XmlHttpRequest setup

            this.NativeId = XHR_Create(HTTPRequest.MethodNames[(byte)CurrentRequest.MethodType],
                                       CurrentRequest.CurrentUri.OriginalString,
                                       CurrentRequest.Credentials != null ? CurrentRequest.Credentials.UserName : null,
                                       CurrentRequest.Credentials != null ? CurrentRequest.Credentials.Password : null,
                                       CurrentRequest.WithCredentials ? 1 : 0);
            Connections.Add(NativeId, this);

            CurrentRequest.EnumerateHeaders((header, values) =>
            {
                if (!header.Equals("Content-Length"))
                {
                    for (int i = 0; i < values.Count; ++i)
                    {
                        XHR_SetRequestHeader(NativeId, header, values[i]);
                    }
                }
            }, /*callBeforeSendCallback:*/ true);

            XHR_SetResponseHandler(NativeId, WebGLConnection.OnResponse, WebGLConnection.OnError, WebGLConnection.OnTimeout, WebGLConnection.OnAborted);
            // Setting OnUploadProgress result in an addEventListener("progress", ...) call making the request non-simple.
            // https://forum.unity.com/threads/best-http-released.200006/page-49#post-3696220
            XHR_SetProgressHandler(NativeId,
                                   CurrentRequest.OnDownloadProgress == null ? (OnWebGLProgressDelegate)null : WebGLConnection.OnDownloadProgress,
                                   CurrentRequest.OnUploadProgress == null ? (OnWebGLProgressDelegate)null : WebGLConnection.OnUploadProgress);

            XHR_SetTimeout(NativeId, (uint)(CurrentRequest.ConnectTimeout.TotalMilliseconds + CurrentRequest.Timeout.TotalMilliseconds));

            byte[] body              = CurrentRequest.GetEntityBody();
            int    length            = 0;
            bool   releaseBodyBuffer = false;

            if (body == null)
            {
                var upStreamInfo = CurrentRequest.GetUpStream();
                if (upStreamInfo.Stream != null)
                {
                    var internalBuffer = BufferPool.Get(upStreamInfo.Length > 0 ? upStreamInfo.Length : HTTPRequest.UploadChunkSize, true);
                    using (BufferPoolMemoryStream ms = new BufferPoolMemoryStream(internalBuffer, 0, internalBuffer.Length, true, true, false, true))
                    {
                        var buffer    = BufferPool.Get(HTTPRequest.UploadChunkSize, true);
                        int readCount = -1;
                        while ((readCount = upStreamInfo.Stream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            ms.Write(buffer, 0, readCount);
                        }

                        BufferPool.Release(buffer);

                        length = (int)ms.Position;
                        body   = ms.GetBuffer();

                        releaseBodyBuffer = true;
                    }
                }
            }
            else
            {
                length = body.Length;

                XHR_Send(NativeId, body, length);
            }

            XHR_Send(NativeId, body, length);

            if (releaseBodyBuffer)
            {
                BufferPool.Release(body);
            }
        }
Пример #16
0
        protected void ReadUnknownSize(Stream stream)
        {
            // Progress report:
            long Downloaded          = 0;
            long DownloadLength      = 0;
            bool sendProgressChanged = this.baseRequest.OnDownloadProgress != null && (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";

            Decompression.GZipDecompressor decompressor = gzipped ? new Decompression.GZipDecompressor(256) : null;

            using (var output = new BufferPoolMemoryStream())
            {
                byte[] buffer = BufferPool.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
                    {
                        if (this.baseRequest.IsCancellationRequested)
                        {
                            return;
                        }

                        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:
                        Downloaded    += bytes;
                        DownloadLength = Downloaded;

                        if (sendProgressChanged)
                        {
                            RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, Downloaded, DownloadLength));
                        }
                    } while (readBytes < buffer.Length && bytes > 0);

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

                BufferPool.Release(buffer);

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

                    FlushRemainingFragmentBuffer();
                }

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

            if (decompressor != null)
            {
                decompressor.Dispose();
            }
        }
Пример #17
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();
        }
        void OnResponse(int httpStatus, byte[] buffer, int bufferLength)
        {
            HTTPConnectionStates proposedConnectionState = HTTPConnectionStates.Processing;
            bool resendRequest = false;

            try
            {
                if (this.CurrentRequest.IsCancellationRequested)
                {
                    return;
                }

                using (var ms = new BufferPoolMemoryStream())
                {
                    Stream = ms;

                    XHR_GetStatusLine(NativeId, OnBufferCallback);
                    XHR_GetResponseHeaders(NativeId, OnBufferCallback);

                    if (buffer != null && bufferLength > 0)
                    {
                        ms.Write(buffer, 0, bufferLength);
                    }

                    ms.Seek(0L, SeekOrigin.Begin);

                    var    internalBuffer = ms.GetBuffer();
                    string tmp            = System.Text.Encoding.UTF8.GetString(internalBuffer);
                    HTTPManager.Logger.Information(this.NativeId + " OnResponse - full response ", tmp, this.Context);

                    SupportedProtocols protocol = CurrentRequest.ProtocolHandler == SupportedProtocols.Unknown ? HTTPProtocolFactory.GetProtocolFromUri(CurrentRequest.CurrentUri) : CurrentRequest.ProtocolHandler;
                    CurrentRequest.Response = HTTPProtocolFactory.Get(protocol, CurrentRequest, ms, CurrentRequest.UseStreaming, false);

                    CurrentRequest.Response.Receive(buffer != null && bufferLength > 0 ? (int)bufferLength : -1, true);

                    KeepAliveHeader keepAlive = null;
                    ConnectionHelper.HandleResponse(this.ToString(), this.CurrentRequest, out resendRequest, out proposedConnectionState, ref keepAlive);
                }
            }
            catch (Exception e)
            {
                HTTPManager.Logger.Exception(this.NativeId + " WebGLConnection", "OnResponse", e, this.Context);

                if (this.ShutdownType == ShutdownTypes.Immediate)
                {
                    return;
                }

#if !BESTHTTP_DISABLE_CACHING
                if (this.CurrentRequest.UseStreaming)
                {
                    HTTPCacheService.DeleteEntity(this.CurrentRequest.CurrentUri);
                }
#endif

                // Something gone bad, Response must be null!
                this.CurrentRequest.Response = null;

                if (!this.CurrentRequest.IsCancellationRequested)
                {
                    this.CurrentRequest.Exception = e;
                    this.CurrentRequest.State     = HTTPRequestStates.Error;
                }

                proposedConnectionState = HTTPConnectionStates.Closed;
            }
            finally
            {
                // Exit ASAP
                if (this.ShutdownType != ShutdownTypes.Immediate)
                {
                    if (this.CurrentRequest.IsCancellationRequested)
                    {
                        // we don't know what stage the request is cancelled, we can't safely reuse the tcp channel.
                        proposedConnectionState = HTTPConnectionStates.Closed;

                        this.CurrentRequest.Response = null;

                        this.CurrentRequest.State = this.CurrentRequest.IsTimedOut ? HTTPRequestStates.TimedOut : HTTPRequestStates.Aborted;
                    }
                    else if (resendRequest)
                    {
                        RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.CurrentRequest, RequestEvents.Resend));
                    }
                    else if (this.CurrentRequest.Response != null && this.CurrentRequest.Response.IsUpgraded)
                    {
                        proposedConnectionState = HTTPConnectionStates.WaitForProtocolShutdown;
                    }
                    else if (this.CurrentRequest.State == HTTPRequestStates.Processing)
                    {
                        if (this.CurrentRequest.Response != null)
                        {
                            this.CurrentRequest.State = HTTPRequestStates.Finished;
                        }
                        else
                        {
                            this.CurrentRequest.Exception = new Exception(string.Format("[{0}] Remote server closed the connection before sending response header! Previous request state: {1}. Connection state: {2}",
                                                                                        this.ToString(),
                                                                                        this.CurrentRequest.State.ToString(),
                                                                                        this.State.ToString()));
                            this.CurrentRequest.State = HTTPRequestStates.Error;

                            proposedConnectionState = HTTPConnectionStates.Closed;
                        }
                    }

                    this.CurrentRequest = null;

                    if (proposedConnectionState == HTTPConnectionStates.Processing)
                    {
                        proposedConnectionState = HTTPConnectionStates.Closed;
                    }

                    ConnectionEventHelper.EnqueueConnectionEvent(new ConnectionEventInfo(this, proposedConnectionState));
                }
            }
        }
Пример #19
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 = BufferPool.Get(Mathf.NextPowerOfTwo(chunkLength), true);

                int contentLength = 0;

                // Progress report:
                long Downloaded          = 0;
                long DownloadLength      = hasContentLengthHeader ? realLength : chunkLength;
                bool sendProgressChanged = this.baseRequest.OnDownloadProgress != null && (this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                                                           || this.IsFromCache
#endif
                                                                                           );

                if (sendProgressChanged)
                {
                    RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, Downloaded, DownloadLength));
                }

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

                Decompression.GZipDecompressor decompressor = gzipped ? new Decompression.GZipDecompressor(256) : null;

                while (chunkLength != 0)
                {
                    if (this.baseRequest.IsCancellationRequested)
                    {
                        return;
                    }

                    // To avoid more GC garbage we use only one buffer, and resize only if the next chunk doesn't fit.
                    if (buffer.Length < chunkLength)
                    {
                        BufferPool.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
                        Downloaded += bytes;

                        if (sendProgressChanged)
                        {
                            RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, Downloaded, DownloadLength));
                        }
                    } while (readBytes < chunkLength);

                    if (baseRequest.UseStreaming)
                    {
                        if (gzipped)
                        {
                            var decompressed = decompressor.Decompress(buffer, 0, readBytes, false, true);
                            if (decompressed.Data != null)
                            {
                                FeedStreamFragment(decompressed.Data, 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 && sendProgressChanged)
                    {
                        RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, Downloaded, DownloadLength));
                    }
                }

                BufferPool.Release(buffer);

                if (baseRequest.UseStreaming)
                {
                    if (gzipped)
                    {
                        var decompressed = decompressor.Decompress(null, 0, 0, true, true);
                        if (decompressed.Data != null)
                        {
                            FeedStreamFragment(decompressed.Data, 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);
                }

                if (decompressor != null)
                {
                    decompressor.Dispose();
                }
            }
        }
Пример #20
0
        public unsafe RawFrameData Get()
        {
            if (Data == null)
            {
                Data = BufferPool.NoData;
            }

            using (var ms = new BufferPoolMemoryStream(this.DataLength + 9))
            {
                // For the complete documentation for this section see:
                // http://tools.ietf.org/html/rfc6455#section-5.2

                // Write the header
                ms.WriteByte(this.Header);

                // The length of the "Payload data", in bytes: if 0-125, that is the payload length.  If 126, the following 2 bytes interpreted as a
                // 16-bit unsigned integer are the payload length.  If 127, the following 8 bytes interpreted as a 64-bit unsigned integer (the
                // most significant bit MUST be 0) are the payload length.  Multibyte length quantities are expressed in network byte order.
                if (this.DataLength < 126)
                {
                    ms.WriteByte((byte)(0x80 | (byte)this.DataLength));
                }
                else if (this.DataLength < UInt16.MaxValue)
                {
                    ms.WriteByte((byte)(0x80 | 126));
                    byte[] len = BitConverter.GetBytes((UInt16)this.DataLength);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(len, 0, len.Length);
                    }

                    ms.Write(len, 0, len.Length);
                }
                else
                {
                    ms.WriteByte((byte)(0x80 | 127));
                    byte[] len = BitConverter.GetBytes((UInt64)this.DataLength);
                    if (BitConverter.IsLittleEndian)
                    {
                        Array.Reverse(len, 0, len.Length);
                    }

                    ms.Write(len, 0, len.Length);
                }

                // All frames sent from the client to the server are masked by a 32-bit value that is contained within the frame.  This field is
                // present if the mask bit is set to 1 and is absent if the mask bit is set to 0.
                // If the data is being sent by the client, the frame(s) MUST be masked.
                byte[] mask = BufferPool.Get(4, true);

                int hash = this.GetHashCode();

                mask[0] = (byte)((hash >> 24) & 0xFF);
                mask[1] = (byte)((hash >> 16) & 0xFF);
                mask[2] = (byte)((hash >> 8) & 0xFF);
                mask[3] = (byte)(hash & 0xFF);

                ms.Write(mask, 0, 4);

                // Do the masking.
                fixed(byte *pData = Data, pmask = mask)
                {
                    // Here, instead of byte by byte, we reinterpret cast the data as uints and apply the masking so.
                    // This way, we can mask 4 bytes in one cycle, instead of just 1
                    int localLength = this.DataLength / 4;

                    if (localLength > 0)
                    {
                        uint *upData = (uint *)pData;
                        uint  umask  = *(uint *)pmask;

                        unchecked
                        {
                            for (int i = 0; i < localLength; ++i)
                            {
                                upData[i] = upData[i] ^ umask;
                            }
                        }
                    }

                    // Because data might not be exactly dividable by 4, we have to mask the remaining 0..3 too.
                    int from = localLength * 4;

                    localLength = from + this.DataLength % 4;
                    for (int i = from; i < localLength; ++i)
                    {
                        pData[i] = (byte)(pData[i] ^ pmask[i % 4]);
                    }
                }

                BufferPool.Release(mask);

                ms.Write(Data, 0, DataLength);

                return(new RawFrameData(ms.ToArray(true), (int)ms.Length));
            }
        }
Пример #21
0
        // No transfer-encoding just raw bytes.
        internal void ReadRaw(Stream stream, long contentLength)
        {
            BeginReceiveStreamFragments();

            // Progress report:
            long downloaded          = 0;
            long downloadLength      = contentLength;
            bool sendProgressChanged = this.baseRequest.OnDownloadProgress != null && (this.IsSuccess
#if !BESTHTTP_DISABLE_CACHING
                                                                                       || this.IsFromCache
#endif
                                                                                       );

            if (sendProgressChanged)
            {
                RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, downloaded, downloadLength));
            }

            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";

            Decompression.GZipDecompressor decompressor = gzipped ? new Decompression.GZipDecompressor(256) : null;

            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))
            {
                // Because of the last parameter, buffer's size can be larger than the requested but there's no reason to use
                //  an exact sized one if there's an larger one available in the pool. Later we will use the whole buffer.
                byte[] buffer    = BufferPool.Get(Math.Max(baseRequest.StreamFragmentSize, MinBufferSize), true);
                int    readBytes = 0;

                while (contentLength > 0)
                {
                    if (this.baseRequest.IsCancellationRequested)
                    {
                        return;
                    }

                    readBytes = 0;

                    do
                    {
                        // tryToReadCount contain how much bytes we want to read in once. We try to read the buffer fully in once,
                        //  but with a limit of the remaining contentLength.
                        int tryToReadCount = (int)Math.Min(Math.Min(int.MaxValue, contentLength), buffer.Length - readBytes);

                        int bytes = stream.Read(buffer, readBytes, tryToReadCount);

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

                        readBytes     += bytes;
                        contentLength -= bytes;

                        // Progress report:
                        if (sendProgressChanged)
                        {
                            downloaded += bytes;
                            RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(this.baseRequest, RequestEvents.DownloadProgress, downloaded, downloadLength));
                        }
                    } while (readBytes < buffer.Length && contentLength > 0);

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

                BufferPool.Release(buffer);

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

                    FlushRemainingFragmentBuffer();
                }

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

            if (decompressor != null)
            {
                decompressor.Dispose();
            }
        }
Пример #22
0
        void OnResponse(int httpStatus, byte[] buffer, int bufferLength)
        {
            try
            {
                using (var ms = new BufferPoolMemoryStream())
                {
                    Stream = ms;

                    XHR_GetStatusLine(NativeId, OnBufferCallback);
                    XHR_GetResponseHeaders(NativeId, OnBufferCallback);

                    if (buffer != null && bufferLength > 0)
                    {
                        ms.Write(buffer, 0, bufferLength);
                    }

                    ms.Seek(0L, SeekOrigin.Begin);

                    var    internalBuffer = ms.GetBuffer();
                    string tmp            = System.Text.Encoding.UTF8.GetString(internalBuffer);
                    HTTPManager.Logger.Information(this.NativeId + " OnResponse - full response ", tmp);

                    SupportedProtocols protocol = CurrentRequest.ProtocolHandler == SupportedProtocols.Unknown ? HTTPProtocolFactory.GetProtocolFromUri(CurrentRequest.CurrentUri) : CurrentRequest.ProtocolHandler;
                    CurrentRequest.Response = HTTPProtocolFactory.Get(protocol, CurrentRequest, ms, CurrentRequest.UseStreaming, false);

                    CurrentRequest.Response.Receive(buffer != null && bufferLength > 0 ? (int)bufferLength : -1, true);

#if !BESTHTTP_DISABLE_COOKIES
                    if (CurrentRequest.IsCookiesEnabled)
                    {
                        BestHTTP.Cookies.CookieJar.Set(CurrentRequest.Response);
                    }
#endif
                }
            }
            catch (Exception e)
            {
                HTTPManager.Logger.Exception(this.NativeId + " WebGLConnection", "OnResponse", e);

                if (CurrentRequest != null)
                {
                    // Something gone bad, Response must be null!
                    CurrentRequest.Response = null;

                    switch (State)
                    {
                    case HTTPConnectionStates.AbortRequested:
                        CurrentRequest.State = HTTPRequestStates.Aborted;
                        break;

                    case HTTPConnectionStates.TimedOut:
                        CurrentRequest.State = HTTPRequestStates.TimedOut;
                        break;

                    default:
                        CurrentRequest.Exception = e;
                        CurrentRequest.State     = HTTPRequestStates.Error;
                        break;
                    }
                }
            }
            finally
            {
                Connections.Remove(NativeId);

                Stream = null;

                if (CurrentRequest != null)
                {
                    lock (HTTPManager.Locker)
                    {
                        State = HTTPConnectionStates.Closed;
                        if (CurrentRequest.State == HTTPRequestStates.Processing)
                        {
                            if (CurrentRequest.Response != null)
                            {
                                CurrentRequest.State = HTTPRequestStates.Finished;
                            }
                            else
                            {
                                CurrentRequest.State = HTTPRequestStates.Error;
                            }
                        }
                    }
                }

                LastProcessTime = DateTime.UtcNow;

                if (OnConnectionRecycled != null)
                {
                    RecycleNow();
                }

                XHR_Release(NativeId);
            }
        }