Exemple #1
0
 public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool)
 {
     this.reader     = reader;
     this.writer     = writer;
     buffer          = bufferPool.GetBuffer();
     this.bufferPool = bufferPool;
 }
        /// <summary>
        ///     Determines whether the stream starts with the given string.
        /// </summary>
        /// <returns>
        ///     1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
        /// </returns>
        private static async Task <int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, string expectedStart, CancellationToken cancellationToken = default)
        {
            const int lengthToCheck = 10;

            byte[] buffer = null;
            try
            {
                if (bufferPool.BufferSize < lengthToCheck)
                {
                    throw new Exception($"Buffer is too small. Minimum size is {lengthToCheck} bytes");
                }

                buffer = bufferPool.GetBuffer(bufferPool.BufferSize);

                bool isExpected = true;
                int  i          = 0;
                while (i < lengthToCheck)
                {
                    int peeked = await clientStreamReader.PeekBytesAsync(buffer, i, i, lengthToCheck - i, cancellationToken);

                    if (peeked <= 0)
                    {
                        return(-1);
                    }

                    peeked += i;

                    while (i < peeked)
                    {
                        int b = buffer[i];

                        if (b == ' ' && i > 2)
                        {
                            return(isExpected ? 1 : 0);
                        }
                        else
                        {
                            char ch = (char)b;
                            if (ch < 'A' || ch > 'z' || (ch > 'Z' && ch < 'a')) // ASCII letter
                            {
                                return(-1);
                            }
                            else if (i >= expectedStart.Length || ch != expectedStart[i])
                            {
                                isExpected = false;
                            }
                        }

                        i++;
                    }
                }

                // only letters
                return(0);
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
 public CopyStream(ICustomStreamReader reader, ICustomStreamWriter writer, IBufferPool bufferPool, int bufferSize)
 {
     this.reader = reader;
     this.writer = writer;
     BufferSize  = bufferSize;
     buffer      = bufferPool.GetBuffer(bufferSize);
 }
        /// <summary>
        ///     Determines whether the stream starts with the given string.
        /// </summary>
        /// <param name="clientStreamReader">The client stream reader.</param>
        /// <param name="expectedStart">The expected start.</param>
        /// <returns>
        ///     1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
        /// </returns>
        private static async Task <int> startsWith(ICustomStreamReader clientStreamReader, string expectedStart)
        {
            bool isExpected   = true;
            int  legthToCheck = 10;

            for (int i = 0; i < legthToCheck; i++)
            {
                int b = await clientStreamReader.PeekByteAsync(i);

                if (b == -1)
                {
                    return(-1);
                }

                if (b == ' ' && i > 2)
                {
                    return(isExpected ? 1 : 0);
                }

                char ch = (char)b;
                if (!char.IsLetter(ch))
                {
                    return(-1);
                }

                if (i >= expectedStart.Length || ch != expectedStart[i])
                {
                    isExpected = false;
                }
            }

            // only letters
            return(isExpected ? 1 : 0);
        }
        /// <summary>
        ///     Copies the streams chunked
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="onCopy"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task copyBodyChunkedAsync(ICustomStreamReader reader, Action <byte[], int, int> onCopy,
                                                CancellationToken cancellationToken)
        {
            while (true)
            {
                string chunkHead = await reader.ReadLineAsync(cancellationToken);

                int idx = chunkHead.IndexOf(";");
                if (idx >= 0)
                {
                    chunkHead = chunkHead.Substring(0, idx);
                }

                int chunkSize = int.Parse(chunkHead, NumberStyles.HexNumber);

                await WriteLineAsync(chunkHead, cancellationToken);

                if (chunkSize != 0)
                {
                    await copyBytesFromStream(reader, chunkSize, onCopy, cancellationToken);
                }

                await WriteLineAsync(cancellationToken);

                // chunk trail
                await reader.ReadLineAsync(cancellationToken);

                if (chunkSize == 0)
                {
                    break;
                }
            }
        }
        /// <summary>
        /// Read a line from the byte stream
        /// </summary>
        /// <returns></returns>
        private async Task <long> readUntilBoundaryAsync(ICustomStreamReader reader, long totalBytesToRead, string boundary, CancellationToken cancellationToken)
        {
            int bufferDataLength = 0;

            var buffer = bufferPool.GetBuffer(bufferSize);

            try
            {
                int  boundaryLength = boundary.Length + 4;
                long bytesRead      = 0;

                while (bytesRead < totalBytesToRead && (reader.DataAvailable || await reader.FillBufferAsync(cancellationToken)))
                {
                    byte newChar = reader.ReadByteFromBuffer();
                    buffer[bufferDataLength] = newChar;

                    bufferDataLength++;
                    bytesRead++;

                    if (bufferDataLength >= boundaryLength)
                    {
                        int startIdx = bufferDataLength - boundaryLength;
                        if (buffer[startIdx] == '-' && buffer[startIdx + 1] == '-')
                        {
                            startIdx += 2;
                            bool ok = true;
                            for (int i = 0; i < boundary.Length; i++)
                            {
                                if (buffer[startIdx + i] != boundary[i])
                                {
                                    ok = false;
                                    break;
                                }
                            }

                            if (ok)
                            {
                                break;
                            }
                        }
                    }

                    if (bufferDataLength == buffer.Length)
                    {
                        // boundary is not longer than 70 bytes according to the specification, so keeping the last 100 (minimum 74) bytes is enough
                        const int bytesToKeep = 100;
                        Buffer.BlockCopy(buffer, buffer.Length - bytesToKeep, buffer, 0, bytesToKeep);
                        bufferDataLength = bytesToKeep;
                    }
                }

                return(bytesRead);
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
Exemple #7
0
 internal LimitedStream(ICustomStreamReader baseStream, bool isChunked,
                        long contentLength)
 {
     this.baseStream = baseStream;
     this.isChunked  = isChunked;
     bytesRemaining  = isChunked
         ? 0
         : contentLength == -1
             ? long.MaxValue
             : contentLength;
 }
        internal static async Task ReadHeaders(ICustomStreamReader reader, HeaderCollection headerCollection,
                                               CancellationToken cancellationToken)
        {
            string tmpLine;

            while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync(cancellationToken)))
            {
                var header = tmpLine.Split(ProxyConstants.ColonSplit, 2);
                headerCollection.AddHeader(header[0], header[1]);
            }
        }
Exemple #9
0
        /// <summary>
        ///     Determines whether the stream starts with the given string.
        /// </summary>
        /// <param name="clientStreamReader">The client stream reader.</param>
        /// <param name="expectedStart">The expected start.</param>
        /// <returns>
        ///     1: when starts with the given string, 0: when valid HTTP method, -1: otherwise
        /// </returns>
        private static async Task <int> startsWith(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, string expectedStart, CancellationToken cancellationToken = default)
        {
            int       iRet          = -1;
            const int lengthToCheck = 10;

            byte[] buffer = null;
            try
            {
                buffer = bufferPool.GetBuffer(Math.Max(bufferSize, lengthToCheck));

                int peeked = await clientStreamReader.PeekBytesAsync(buffer, 0, 0, lengthToCheck, cancellationToken);

                if (peeked > 0)
                {
                    bool isExpected = true;

                    for (int i = 0; i < lengthToCheck; i++)
                    {
                        int b = buffer[i];

                        if (b == ' ' && i > 2)
                        {
                            return(isExpected ? 1 : 0);
                        }
                        else
                        {
                            char ch = (char)b;
                            if (!char.IsLetter(ch))
                            {
                                return(-1);
                            }
                            else if (i >= expectedStart.Length || ch != expectedStart[i])
                            {
                                isExpected = false;
                            }
                        }
                    }

                    // only letters
                    iRet = isExpected ? 1 : 0;
                }
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
                buffer = null;
            }
            return(iRet);
        }
Exemple #10
0
        internal static async Task ReadHeaders(ICustomStreamReader reader, HeaderCollection headerCollection,
                                               CancellationToken cancellationToken)
        {
            string?tmpLine;

            while (!string.IsNullOrEmpty(tmpLine = await reader.ReadLineAsync(cancellationToken)))
            {
                int colonIndex = tmpLine !.IndexOf(':');
                if (colonIndex == -1)
                {
                    throw new Exception("Header line should contain a colon character.");
                }

                string headerName  = tmpLine.AsSpan(0, colonIndex).ToString();
                string headerValue = tmpLine.AsSpan(colonIndex + 1).ToString();
                headerCollection.AddHeader(headerName, headerValue);
            }
        }
        /// <summary>
        ///     Copies the specified content length number of bytes to the output stream from the given inputs stream
        ///     optionally chunked
        /// </summary>
        /// <param name="streamReader"></param>
        /// <param name="isChunked"></param>
        /// <param name="contentLength"></param>
        /// <param name="onCopy"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        internal Task CopyBodyAsync(ICustomStreamReader streamReader, bool isChunked, long contentLength,
                                    Action <byte[], int, int> onCopy, CancellationToken cancellationToken)
        {
            // For chunked request we need to read data as they arrive, until we reach a chunk end symbol
            if (isChunked)
            {
                return(copyBodyChunkedAsync(streamReader, onCopy, cancellationToken));
            }

            // http 1.0 or the stream reader limits the stream
            if (contentLength == -1)
            {
                contentLength = long.MaxValue;
            }

            // If not chunked then its easy just read the amount of bytes mentioned in content length header
            return(copyBytesFromStream(streamReader, contentLength, onCopy, cancellationToken));
        }
        /// <summary>
        ///     Copies the specified bytes to the stream from the input stream
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="count"></param>
        /// <param name="onCopy"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        private async Task copyBytesFromStream(ICustomStreamReader reader, long count, Action <byte[], int, int> onCopy,
                                               CancellationToken cancellationToken)
        {
            var buffer = bufferPool.GetBuffer(BufferSize);

            try
            {
                long remainingBytes = count;

                while (remainingBytes > 0)
                {
                    int bytesToRead = buffer.Length;
                    if (remainingBytes < bytesToRead)
                    {
                        bytesToRead = (int)remainingBytes;
                    }

                    int bytesRead = await reader.ReadAsync(buffer, 0, bytesToRead, cancellationToken);

                    if (bytesRead == 0)
                    {
                        break;
                    }

                    remainingBytes -= bytesRead;

                    await stream.WriteAsync(buffer, 0, bytesRead, cancellationToken);

                    onCopy?.Invoke(buffer, 0, bytesRead);
                }
            }
            finally
            {
                bufferPool.ReturnBuffer(buffer);
            }
        }
 /// <summary>
 ///     Determines whether is connect method.
 /// </summary>
 /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
 internal static Task <int> IsConnectMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, CancellationToken cancellationToken = default)
 {
     return(startsWith(clientStreamReader, bufferPool, "CONNECT", cancellationToken));
 }
 /// <summary>
 ///     Determines whether is connect method.
 /// </summary>
 /// <param name="clientStreamReader">The client stream reader.</param>
 /// <returns>1: when CONNECT, 0: when valid HTTP method, -1: otherwise</returns>
 internal static Task <int> IsConnectMethod(ICustomStreamReader clientStreamReader)
 {
     return(startsWith(clientStreamReader, "CONNECT"));
 }
 /// <summary>
 ///     Determines whether is pri method (HTTP/2).
 /// </summary>
 /// <param name="clientStreamReader">The client stream reader.</param>
 /// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
 internal static Task <int> IsPriMethod(ICustomStreamReader clientStreamReader)
 {
     return(startsWith(clientStreamReader, "PRI"));
 }
Exemple #16
0
 public PdfReaderInternal(byte[] bytes)
 {
     reader = new CustomStreamReader(bytes);
 }
Exemple #17
0
 /// <summary>
 ///     Determines whether is pri method (HTTP/2).
 /// </summary>
 /// <param name="clientStreamReader">The client stream reader.</param>
 /// <returns>1: when PRI, 0: when valid HTTP method, -1: otherwise</returns>
 internal static Task <int> IsPriMethod(ICustomStreamReader clientStreamReader, IBufferPool bufferPool, int bufferSize, CancellationToken cancellationToken = default)
 {
     return(startsWith(clientStreamReader, bufferPool, bufferSize, "PRI", cancellationToken));
 }
 internal CustomBufferedPeekStream(ICustomStreamReader baseStream, IBufferPool bufferPool, int startPosition = 0)
 {
     this.bufferPool = bufferPool;
     this.baseStream = baseStream;
     Position        = startPosition;
 }