private void ParseChunkedTrailer(SocketInput input)
            {
                var scan     = input.ConsumingStart();
                var consumed = scan;

                try
                {
                    var ch1 = scan.Take();
                    var ch2 = scan.Take();

                    if (ch1 == -1 || ch2 == -1)
                    {
                        return;
                    }
                    else if (ch1 == '\r' && ch2 == '\n')
                    {
                        consumed = scan;
                        _mode    = Mode.Complete;
                    }
                    else
                    {
                        _mode = Mode.TrailerHeaders;
                    }
                }
                finally
                {
                    input.ConsumingComplete(consumed, scan);
                }
            }
            private void ParseChunkedPrefix(SocketInput input)
            {
                var scan     = input.ConsumingStart();
                var consumed = scan;

                try
                {
                    var ch1 = scan.Take();
                    var ch2 = scan.Take();
                    if (ch1 == -1 || ch2 == -1)
                    {
                        return;
                    }

                    var chunkSize = CalculateChunkSize(ch1, 0);
                    ch1 = ch2;

                    do
                    {
                        if (ch1 == ';')
                        {
                            consumed = scan;

                            _inputLength = chunkSize;
                            _mode        = Mode.Extension;
                            return;
                        }

                        ch2 = scan.Take();
                        if (ch2 == -1)
                        {
                            return;
                        }

                        if (ch1 == '\r' && ch2 == '\n')
                        {
                            consumed     = scan;
                            _inputLength = chunkSize;

                            if (chunkSize > 0)
                            {
                                _mode = Mode.Data;
                            }
                            else
                            {
                                _mode = Mode.Trailer;
                            }

                            return;
                        }

                        chunkSize = CalculateChunkSize(ch1, chunkSize);
                        ch1       = ch2;
                    } while (ch1 != -1);
                }
                finally
                {
                    input.ConsumingComplete(consumed, scan);
                }
            }
            private void ParseChunkedSuffix(SocketInput input)
            {
                var scan     = input.ConsumingStart();
                var consumed = scan;

                try
                {
                    var ch1 = scan.Take();
                    var ch2 = scan.Take();
                    if (ch1 == -1 || ch2 == -1)
                    {
                        return;
                    }
                    else if (ch1 == '\r' && ch2 == '\n')
                    {
                        consumed = scan;
                        _mode    = Mode.Prefix;
                    }
                    else
                    {
                        ThrowBadRequestException("Bad chunk suffix");
                    }
                }
                finally
                {
                    input.ConsumingComplete(consumed, scan);
                }
            }
        public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
        {
            _socket           = socket;
            socket.Connection = this;
            ConnectionControl = this;

            ConnectionId = GenerateConnectionId(Interlocked.Increment(ref _lastConnectionId));

            _rawSocketInput  = new SocketInput(Memory, ThreadPool);
            _rawSocketOutput = new SocketOutput(Thread, _socket, Memory, this, ConnectionId, Log, ThreadPool, WriteReqPool);
        }
            private void ParseExtension(SocketInput input)
            {
                var scan     = input.ConsumingStart();
                var consumed = scan;

                try
                {
                    // Chunk-extensions not currently parsed
                    // Just drain the data
                    do
                    {
                        if (scan.Seek(ref _vectorCRs) == -1)
                        {
                            // End marker not found yet
                            consumed = scan;
                            return;
                        }
                        ;

                        var ch1 = scan.Take();
                        var ch2 = scan.Take();

                        if (ch2 == '\n')
                        {
                            consumed = scan;
                            if (_inputLength > 0)
                            {
                                _mode = Mode.Data;
                            }
                            else
                            {
                                _mode = Mode.Trailer;
                            }
                        }
                        else if (ch2 == -1)
                        {
                            return;
                        }
                    } while (_mode == Mode.Extension);
                }
                finally
                {
                    input.ConsumingComplete(consumed, scan);
                }
            }
        public Task StopAsync()
        {
            lock (_stateLock)
            {
                switch (_connectionState)
                {
                case ConnectionState.SocketClosed:
                    return(TaskUtilities.CompletedTask);

                case ConnectionState.CreatingFrame:
                    _connectionState = ConnectionState.ToDisconnect;
                    break;

                case ConnectionState.Open:
                    _frame.Stop();
                    SocketInput.CompleteAwaiting();
                    break;
                }

                _socketClosedTcs = new TaskCompletionSource <object>();
                return(_socketClosedTcs.Task);
            }
        }
            private int ReadChunkedData(SocketInput input, byte[] buffer, int offset, int count)
            {
                var scan = input.ConsumingStart();
                int actual;

                try
                {
                    var limit = buffer == null ? _inputLength : Math.Min(count, _inputLength);
                    scan          = scan.CopyTo(buffer, offset, limit, out actual);
                    _inputLength -= actual;
                }
                finally
                {
                    input.ConsumingComplete(scan, scan);
                }

                if (_inputLength == 0)
                {
                    _mode = Mode.Suffix;
                }

                return(actual);
            }
        private static async Task <int> ReadAsyncAwaited(this SocketInput input, byte[] buffer, int offset, int count)
        {
            while (true)
            {
                await input;

                var fin = input.RemoteIntakeFin;

                var begin = input.ConsumingStart();
                int actual;
                var end = begin.CopyTo(buffer, offset, count, out actual);
                input.ConsumingComplete(end, end);

                if (actual != 0)
                {
                    return(actual);
                }
                else if (fin)
                {
                    return(0);
                }
            }
        }
        public static ValueTask <int> ReadAsync(this SocketInput input, byte[] buffer, int offset, int count)
        {
            while (input.IsCompleted)
            {
                var fin = input.RemoteIntakeFin;

                var begin = input.ConsumingStart();
                int actual;
                var end = begin.CopyTo(buffer, offset, count, out actual);
                input.ConsumingComplete(end, end);

                if (actual != 0)
                {
                    return(actual);
                }
                else if (fin)
                {
                    return(0);
                }
            }

            return(input.ReadAsyncAwaited(buffer, offset, count));
        }
            private async Task <int> ReadStateMachineAsync(SocketInput input, ArraySegment <byte> buffer, CancellationToken cancellationToken)
            {
                while (_mode < Mode.Trailer)
                {
                    while (_mode == Mode.Prefix)
                    {
                        var fin = input.RemoteIntakeFin;

                        ParseChunkedPrefix(input);

                        if (_mode != Mode.Prefix)
                        {
                            break;
                        }
                        else if (fin)
                        {
                            ThrowChunkedRequestIncomplete();
                        }

                        await input;
                    }

                    while (_mode == Mode.Extension)
                    {
                        var fin = input.RemoteIntakeFin;

                        ParseExtension(input);

                        if (_mode != Mode.Extension)
                        {
                            break;
                        }
                        else if (fin)
                        {
                            ThrowChunkedRequestIncomplete();
                        }

                        await input;
                    }

                    while (_mode == Mode.Data)
                    {
                        var fin = input.RemoteIntakeFin;

                        int actual = ReadChunkedData(input, buffer.Array, buffer.Offset, buffer.Count);

                        if (actual != 0)
                        {
                            return(actual);
                        }
                        else if (_mode != Mode.Data)
                        {
                            break;
                        }
                        else if (fin)
                        {
                            ThrowChunkedRequestIncomplete();
                        }

                        await input;
                    }

                    while (_mode == Mode.Suffix)
                    {
                        var fin = input.RemoteIntakeFin;

                        ParseChunkedSuffix(input);

                        if (_mode != Mode.Suffix)
                        {
                            break;
                        }
                        else if (fin)
                        {
                            ThrowChunkedRequestIncomplete();
                        }

                        await input;
                    }
                }

                // Chunks finished, parse trailers
                while (_mode == Mode.Trailer)
                {
                    var fin = input.RemoteIntakeFin;

                    ParseChunkedTrailer(input);

                    if (_mode != Mode.Trailer)
                    {
                        break;
                    }
                    else if (fin)
                    {
                        ThrowChunkedRequestIncomplete();
                    }

                    await input;
                }

                if (_mode == Mode.TrailerHeaders)
                {
                    while (!_context.TakeMessageHeaders(input, _requestHeaders))
                    {
                        if (input.RemoteIntakeFin)
                        {
                            if (_context.TakeMessageHeaders(input, _requestHeaders))
                            {
                                break;
                            }
                            else
                            {
                                ThrowChunkedRequestIncomplete();
                            }
                        }

                        await input;
                    }

                    _mode = Mode.Complete;
                }

                return(0);
            }
Exemple #11
0
        public bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                int chFirst;
                int chSecond;
                while (!scan.IsEnd)
                {
                    var beginName = scan;
                    if (scan.Seek(ref _vectorColons, ref _vectorCRs) == -1)
                    {
                        return(false);
                    }
                    var endName = scan;

                    chFirst = scan.Take();
                    var beginValue = scan;
                    chSecond = scan.Take();

                    if (chFirst == -1 || chSecond == -1)
                    {
                        return(false);
                    }
                    if (chFirst == '\r')
                    {
                        if (chSecond == '\n')
                        {
                            consumed = scan;
                            return(true);
                        }

                        ReportCorruptedHttpRequest(new BadHttpRequestException("Headers corrupted, invalid header sequence."));
                        // Headers corrupted, parsing headers is complete
                        return(true);
                    }

                    while (
                        chSecond == ' ' ||
                        chSecond == '\t' ||
                        chSecond == '\r' ||
                        chSecond == '\n')
                    {
                        if (chSecond == '\r')
                        {
                            var scanAhead = scan;
                            var chAhead   = scanAhead.Take();
                            if (chAhead == -1)
                            {
                                return(false);
                            }
                            else if (chAhead == '\n')
                            {
                                chAhead = scanAhead.Take();
                                if (chAhead == -1)
                                {
                                    return(false);
                                }
                                else if (chAhead != ' ' && chAhead != '\t')
                                {
                                    // If the "\r\n" isn't part of "linear whitespace",
                                    // then this header has no value.
                                    break;
                                }
                            }
                        }

                        beginValue = scan;
                        chSecond   = scan.Take();

                        if (chSecond == -1)
                        {
                            return(false);
                        }
                    }
                    scan = beginValue;

                    var wrapping = false;
                    while (!scan.IsEnd)
                    {
                        if (scan.Seek(ref _vectorCRs) == -1)
                        {
                            // no "\r" in sight, burn used bytes and go back to await more data
                            return(false);
                        }

                        var endValue = scan;
                        chFirst  = scan.Take(); // expecting: \r
                        chSecond = scan.Take(); // expecting: \n

                        if (chSecond == -1)
                        {
                            return(false);
                        }
                        else if (chSecond != '\n')
                        {
                            // "\r" was all by itself, move just after it and try again
                            scan = endValue;
                            scan.Take();
                            continue;
                        }

                        var chThird = scan.Peek();
                        if (chThird == -1)
                        {
                            return(false);
                        }
                        else if (chThird == ' ' || chThird == '\t')
                        {
                            // special case, "\r\n " or "\r\n\t".
                            // this is considered wrapping"linear whitespace" and is actually part of the header value
                            // continue past this for the next
                            wrapping = true;
                            continue;
                        }

                        var name  = beginName.GetArraySegment(endName);
                        var value = beginValue.GetAsciiString(endValue);
                        if (wrapping)
                        {
                            value = value.Replace("\r\n", " ");
                        }

                        consumed = scan;
                        requestHeaders.Append(name.Array, name.Offset, name.Count, value);
                        break;
                    }
                }
                return(false);
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
Exemple #12
0
        protected bool TakeStartLine(SocketInput input)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                string method;
                var    begin = scan;
                if (!begin.GetKnownMethod(ref scan, out method))
                {
                    if (scan.Seek(ref _vectorSpaces) == -1)
                    {
                        return(false);
                    }
                    method = begin.GetAsciiString(scan);
                    scan.Take();
                }

                begin = scan;

                var needDecode = false;
                var chFound    = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks, ref _vectorPercentages);
                if (chFound == -1)
                {
                    return(false);
                }
                else if (chFound == '%')
                {
                    needDecode = true;
                    chFound    = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks);
                    if (chFound == -1)
                    {
                        return(false);
                    }
                }

                var pathBegin = begin;
                var pathEnd   = scan;

                var queryString = "";
                if (chFound == '?')
                {
                    begin = scan;
                    if (scan.Seek(ref _vectorSpaces) != ' ')
                    {
                        return(false);
                    }
                    queryString = begin.GetAsciiString(scan);
                }

                scan.Take();
                begin = scan;

                string httpVersion;
                if (!begin.GetKnownVersion(ref scan, out httpVersion))
                {
                    scan = begin;
                    if (scan.Seek(ref _vectorCRs) == -1)
                    {
                        return(false);
                    }
                    httpVersion = begin.GetAsciiString(scan);

                    scan.Take();
                }
                if (scan.Take() != '\n')
                {
                    return(false);
                }

                // URIs are always encoded/escaped to ASCII https://tools.ietf.org/html/rfc3986#page-11
                // Multibyte Internationalized Resource Identifiers (IRIs) are first converted to utf8;
                // then encoded/escaped to ASCII  https://www.ietf.org/rfc/rfc3987.txt "Mapping of IRIs to URIs"
                string requestUrlPath;
                if (needDecode)
                {
                    // URI was encoded, unescape and then parse as utf8
                    pathEnd        = UrlPathDecoder.Unescape(pathBegin, pathEnd);
                    requestUrlPath = pathBegin.GetUtf8String(pathEnd);
                    requestUrlPath = PathNormalizer.NormalizeToNFC(requestUrlPath);
                }
                else
                {
                    // URI wasn't encoded, parse as ASCII
                    requestUrlPath = pathBegin.GetAsciiString(pathEnd);
                }

                requestUrlPath = PathNormalizer.RemoveDotSegments(requestUrlPath);

                consumed    = scan;
                Method      = method;
                RequestUri  = requestUrlPath;
                QueryString = queryString;
                HttpVersion = httpVersion;

                bool caseMatches;

                if (!string.IsNullOrEmpty(_pathBase) &&
                    (requestUrlPath.Length == _pathBase.Length || (requestUrlPath.Length > _pathBase.Length && requestUrlPath[_pathBase.Length] == '/')) &&
                    RequestUrlStartsWithPathBase(requestUrlPath, out caseMatches))
                {
                    PathBase = caseMatches ? _pathBase : requestUrlPath.Substring(0, _pathBase.Length);
                    Path     = requestUrlPath.Substring(_pathBase.Length);
                }
                else
                {
                    Path = requestUrlPath;
                }

                return(true);
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }