Beispiel #1
0
        public int GetLength(MemoryPoolIterator end)
        {
            if (IsDefault || end.IsDefault)
            {
                return(-1);
            }

            var block  = _block;
            var index  = _index;
            var length = 0;

            checked
            {
                while (true)
                {
                    if (block == end._block)
                    {
                        return(length + end._index - index);
                    }
                    else if (block.Next == null)
                    {
                        throw new InvalidOperationException("end did not follow iterator");
                    }
                    else
                    {
                        length += block.End - index;
                        block   = block.Next;
                        index   = block.Start;
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Checks 9 bytes from <paramref name="begin"/>  correspond to a known HTTP version.
        /// </summary>
        /// <remarks>
        /// A "known HTTP version" Is is either HTTP/1.0 or HTTP/1.1.
        /// Since those fit in 8 bytes, they can be optimally looked up by reading those bytes as a long. Once
        /// in that format, it can be checked against the known versions.
        /// The Known versions will be checked with the required '\r'.
        /// To optimize performance the HTTP/1.1 will be checked first.
        /// </remarks>
        /// <param name="begin">The iterator from which to start the known string lookup.</param>
        /// <param name="knownVersion">A reference to a pre-allocated known string, if the input matches any.</param>
        /// <returns><c>true</c> if the input matches a known string, <c>false</c> otherwise.</returns>
        public static bool GetKnownVersion(this MemoryPoolIterator begin, out string knownVersion)
        {
            knownVersion = null;
            var value = begin.PeekLong();

            if (value == _http11VersionLong)
            {
                knownVersion = Http11Version;
            }
            else if (value == _http10VersionLong)
            {
                knownVersion = Http10Version;
            }

            if (knownVersion != null)
            {
                begin.Skip(knownVersion.Length);

                if (begin.Peek() != '\r')
                {
                    knownVersion = null;
                }
            }

            return(knownVersion != null);
        }
        /// <summary>
        /// Checks that up to 8 bytes from <paramref name="begin"/> correspond to a known HTTP method.
        /// </summary>
        /// <remarks>
        /// A "known HTTP method" can be an HTTP method name defined in the HTTP/1.1 RFC.
        /// Since all of those fit in at most 8 bytes, they can be optimally looked up by reading those bytes as a long. Once
        /// in that format, it can be checked against the known method.
        /// The Known Methods (CONNECT, DELETE, GET, HEAD, PATCH, POST, PUT, OPTIONS, TRACE) are all less than 8 bytes
        /// and will be compared with the required space. A mask is used if the Known method is less than 8 bytes.
        /// To optimize performance the GET method will be checked first.
        /// </remarks>
        /// <param name="begin">The iterator from which to start the known string lookup.</param>
        /// <param name="knownMethod">A reference to a pre-allocated known string, if the input matches any.</param>
        /// <returns><c>true</c> if the input matches a known string, <c>false</c> otherwise.</returns>
        public static bool GetKnownMethod(this MemoryPoolIterator begin, out string knownMethod)
        {
            knownMethod = null;

            ulong value;

            if (!begin.TryPeekLong(out value))
            {
                return(false);
            }

            if ((value & _mask4Chars) == _httpGetMethodLong)
            {
                knownMethod = HttpMethods.Get;
                return(true);
            }
            foreach (var x in _knownMethods)
            {
                if ((value & x.Item1) == x.Item2)
                {
                    knownMethod = x.Item3;
                    return(true);
                }
            }

            return(false);
        }
        public static ArraySegment <byte> PeekArraySegment(this MemoryPoolIterator iter)
        {
            if (iter.IsDefault || iter.IsEnd)
            {
                return(default(ArraySegment <byte>));
            }

            if (iter.Index < iter.Block.End)
            {
                return(new ArraySegment <byte>(iter.Block.Array, iter.Index, iter.Block.End - iter.Index));
            }

            var block = iter.Block.Next;

            while (block != null)
            {
                if (block.Start < block.End)
                {
                    return(new ArraySegment <byte>(block.Array, block.Start, block.End - block.Start));
                }
                block = block.Next;
            }

            // The following should be unreachable due to the IsEnd check above.
            throw new InvalidOperationException("This should be unreachable!");
        }
Beispiel #5
0
        public unsafe static string GetAsciiString(this MemoryPoolIterator start, MemoryPoolIterator end)
        {
            if (start.IsDefault || end.IsDefault)
            {
                return(null);
            }

            var length = start.GetLength(end);

            if (length == 0)
            {
                return(null);
            }

            var inputOffset = start.Index;
            var block       = start.Block;

            var asciiString = new string('\0', length);

            fixed(char *outputStart = asciiString)
            {
                var output    = outputStart;
                var remaining = length;

                var endBlock = end.Block;
                var endIndex = end.Index;

                var outputOffset = 0;

                while (true)
                {
                    int following = (block != endBlock ? block.End : endIndex) - inputOffset;

                    if (following > 0)
                    {
                        if (!AsciiUtilities.TryGetAsciiString(block.DataFixedPtr + inputOffset, output + outputOffset, following))
                        {
                            throw new BadHttpRequestException("The input string contains non-ASCII or null characters.");
                        }

                        outputOffset += following;
                        remaining    -= following;
                    }

                    if (remaining == 0)
                    {
                        break;
                    }

                    block       = block.Next;
                    inputOffset = block.Start;
                }
            }

            return(asciiString);
        }
Beispiel #6
0
        public static ArraySegment <byte> GetArraySegment(this MemoryPoolIterator start, MemoryPoolIterator end)
        {
            if (start.IsDefault || end.IsDefault)
            {
                return(default(ArraySegment <byte>));
            }
            if (end.Block == start.Block)
            {
                return(new ArraySegment <byte>(start.Block.Array, start.Index, end.Index - start.Index));
            }

            var length = start.GetLength(end);
            var array  = new byte[length];

            start.CopyTo(array, 0, length, out length);
            return(new ArraySegment <byte>(array, 0, length));
        }
        public static string GetAsciiStringEscaped(this MemoryPoolIterator start, MemoryPoolIterator end, int maxChars)
        {
            var sb   = new StringBuilder();
            var scan = start;

            while (maxChars > 0 && (scan.Block != end.Block || scan.Index != end.Index))
            {
                var ch = scan.Take();
                sb.Append(ch < 0x20 || ch >= 0x7F ? $"<0x{ch.ToString("X2")}>" : ((char)ch).ToString());
                maxChars--;
            }

            if (scan.Block != end.Block || scan.Index != end.Index)
            {
                sb.Append("...");
            }

            return(sb.ToString());
        }
Beispiel #8
0
        public static string GetUtf8String(this MemoryPoolIterator start, MemoryPoolIterator end)
        {
            if (start.IsDefault || end.IsDefault)
            {
                return(default(string));
            }
            if (end.Block == start.Block)
            {
                return(_utf8.GetString(start.Block.Array, start.Index, end.Index - start.Index));
            }

            var decoder = _utf8.GetDecoder();

            var length     = start.GetLength(end);
            var charLength = length * 2;
            var chars      = new char[charLength];
            var charIndex  = 0;

            var block     = start.Block;
            var index     = start.Index;
            var remaining = length;

            while (true)
            {
                int  bytesUsed;
                int  charsUsed;
                bool completed;
                var  following = block.End - index;
                if (remaining <= following)
                {
                    decoder.Convert(
                        block.Array,
                        index,
                        remaining,
                        chars,
                        charIndex,
                        charLength - charIndex,
                        true,
                        out bytesUsed,
                        out charsUsed,
                        out completed);
                    return(new string(chars, 0, charIndex + charsUsed));
                }
                else if (block.Next == null)
                {
                    decoder.Convert(
                        block.Array,
                        index,
                        following,
                        chars,
                        charIndex,
                        charLength - charIndex,
                        true,
                        out bytesUsed,
                        out charsUsed,
                        out completed);
                    return(new string(chars, 0, charIndex + charsUsed));
                }
                else
                {
                    decoder.Convert(
                        block.Array,
                        index,
                        following,
                        chars,
                        charIndex,
                        charLength - charIndex,
                        false,
                        out bytesUsed,
                        out charsUsed,
                        out completed);
                    charIndex += charsUsed;
                    remaining -= following;
                    block      = block.Next;
                    index      = block.Start;
                }
            }
        }
Beispiel #9
0
        public unsafe int Seek(
            ref Vector <byte> byte0Vector,
            ref Vector <byte> byte1Vector,
            ref Vector <byte> byte2Vector,
            ref MemoryPoolIterator limit)
        {
            if (IsDefault)
            {
                return(-1);
            }

            var block        = _block;
            var index        = _index;
            var wasLastBlock = block.Next == null;
            var following    = block.End - index;

            byte[] array;
            int byte0Index = int.MaxValue;
            int byte1Index = int.MaxValue;
            int byte2Index = int.MaxValue;
            var byte0      = byte0Vector[0];
            var byte1      = byte1Vector[0];
            var byte2      = byte2Vector[0];

            while (true)
            {
                while (following == 0)
                {
                    if ((block == limit.Block && index > limit.Index) ||
                        wasLastBlock)
                    {
                        _block = block;
                        // Ensure iterator is left at limit position
                        _index = limit.Index;
                        return(-1);
                    }
                    block        = block.Next;
                    index        = block.Start;
                    wasLastBlock = block.Next == null;
                    following    = block.End - index;
                }
                array = block.Array;
                while (following > 0)
                {
// Need unit tests to test Vector path
#if !DEBUG
                    // Check will be Jitted away https://github.com/dotnet/coreclr/issues/1079
                    if (Vector.IsHardwareAccelerated)
                    {
#endif
                    if (following >= _vectorSpan)
                    {
                        var data        = new Vector <byte>(array, index);
                        var byte0Equals = Vector.Equals(data, byte0Vector);
                        var byte1Equals = Vector.Equals(data, byte1Vector);
                        var byte2Equals = Vector.Equals(data, byte2Vector);

                        if (!byte0Equals.Equals(Vector <byte> .Zero))
                        {
                            byte0Index = FindFirstEqualByte(ref byte0Equals);
                        }
                        if (!byte1Equals.Equals(Vector <byte> .Zero))
                        {
                            byte1Index = FindFirstEqualByte(ref byte1Equals);
                        }
                        if (!byte2Equals.Equals(Vector <byte> .Zero))
                        {
                            byte2Index = FindFirstEqualByte(ref byte2Equals);
                        }

                        if (byte0Index == int.MaxValue && byte1Index == int.MaxValue && byte2Index == int.MaxValue)
                        {
                            following -= _vectorSpan;
                            index     += _vectorSpan;

                            if (block == limit.Block && index > limit.Index)
                            {
                                _block = block;
                                // Ensure iterator is left at limit position
                                _index = limit.Index;
                                return(-1);
                            }

                            continue;
                        }

                        _block = block;

                        int toReturn, toMove;
                        if (byte0Index < byte1Index)
                        {
                            if (byte0Index < byte2Index)
                            {
                                toReturn = byte0;
                                toMove   = byte0Index;
                            }
                            else
                            {
                                toReturn = byte2;
                                toMove   = byte2Index;
                            }
                        }
                        else
                        {
                            if (byte1Index < byte2Index)
                            {
                                toReturn = byte1;
                                toMove   = byte1Index;
                            }
                            else
                            {
                                toReturn = byte2;
                                toMove   = byte2Index;
                            }
                        }

                        _index = index + toMove;

                        if (block == limit.Block && _index > limit.Index)
                        {
                            // Ensure iterator is left at limit position
                            _index = limit.Index;
                            return(-1);
                        }

                        return(toReturn);
                    }
// Need unit tests to test Vector path
#if !DEBUG
                }
#endif
                    var pCurrent = (block.DataFixedPtr + index);
                    var pEnd     = block == limit.Block ? block.DataFixedPtr + limit.Index + 1 : pCurrent + following;
                    do
                    {
                        if (*pCurrent == byte0)
                        {
                            _block = block;
                            _index = index;
                            return(byte0);
                        }
                        if (*pCurrent == byte1)
                        {
                            _block = block;
                            _index = index;
                            return(byte1);
                        }
                        if (*pCurrent == byte2)
                        {
                            _block = block;
                            _index = index;
                            return(byte2);
                        }
                        pCurrent++;
                        index++;
                    } while (pCurrent != pEnd);

                    following = 0;
                    break;
                }
            }
        }
Beispiel #10
0
        public int Seek(ref Vector <byte> byte0Vector, ref Vector <byte> byte1Vector, ref Vector <byte> byte2Vector)
        {
            var limit = new MemoryPoolIterator();

            return(Seek(ref byte0Vector, ref byte1Vector, ref byte2Vector, ref limit));
        }