상속: ICriticalNotifyCompletion
예제 #1
0
        public static ValueTask <int> ReadAsync(this SocketInput input, byte[] buffer, int offset, int count)
        {
            while (true)
            {
                if (!input.IsCompleted)
                {
                    return(input.ReadAsyncAwaited(buffer, offset, count));
                }

                var begin = input.ConsumingStart();

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

                if (actual != 0)
                {
                    return(actual);
                }
                if (input.RemoteIntakeFin)
                {
                    return(0);
                }
            }
        }
예제 #2
0
        private void OnRead(UvStreamHandle handle, int status, Exception error)
        {
            SocketInput.Unpin(status);

            var normalRead = error == null && status > 0;
            var normalDone = status == 0 || status == -4077 || status == -4095;
            var errorDone  = !(normalDone || normalRead);

            if (normalRead)
            {
                KestrelTrace.Log.ConnectionRead(_connectionId, status);
            }
            else if (normalDone || errorDone)
            {
                KestrelTrace.Log.ConnectionReadFin(_connectionId);
                SocketInput.RemoteIntakeFin = true;
                _socket.ReadStop();

                if (errorDone && error != null)
                {
                    Trace.WriteLine("Connection.OnRead " + error.ToString());
                }
            }


            try
            {
                _frame.Consume();
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Connection._frame.Consume " + ex.ToString());
            }
        }
예제 #3
0
        private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
        {
            var result = SocketInput.IncomingStart(2048);

            return(handle.Libuv.buf_init(
                       result.DataPtr,
                       result.Data.Count));
        }
예제 #4
0
        public void Start()
        {
            KestrelTrace.Log.ConnectionStart(_connectionId);

            SocketInput  = new SocketInput(Memory);
            SocketOutput = new SocketOutput(Thread, _socket);
            _frame       = new Frame(this);
            _socket.ReadStart(_allocCallback, _readCallback, this);
        }
예제 #5
0
        public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
        {
            _socket           = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            _rawSocketInput  = new SocketInput(Memory2);
            _rawSocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
        }
예제 #6
0
        public Connection(ListenerContext context, UvStreamHandle socket) : base(context)
        {
            _socket = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            _rawSocketInput = new SocketInput(Memory2, ThreadPool);
            _rawSocketOutput = new SocketOutput(Thread, _socket, Memory2, this, _connectionId, Log, ThreadPool, WriteReqPool);
        }
예제 #7
0
        private bool TakeStartLine(SocketInput baton)
        {
            var remaining = baton.Buffer;

            if (remaining.Count < 2)
            {
                return(false);
            }
            var firstSpace   = -1;
            var secondSpace  = -1;
            var questionMark = -1;
            var ch0          = remaining.Array[remaining.Offset];

            for (var index = 0; index != remaining.Count - 1; ++index)
            {
                var ch1 = remaining.Array[remaining.Offset + index + 1];
                if (ch0 == '\r' && ch1 == '\n')
                {
                    if (secondSpace == -1)
                    {
                        throw new InvalidOperationException("INVALID REQUEST FORMAT");
                    }
                    Method     = GetString(remaining, 0, firstSpace);
                    RequestUri = GetString(remaining, firstSpace + 1, secondSpace);
                    if (questionMark == -1)
                    {
                        Path        = RequestUri;
                        QueryString = string.Empty;
                    }
                    else
                    {
                        Path        = GetString(remaining, firstSpace + 1, questionMark);
                        QueryString = GetString(remaining, questionMark, secondSpace);
                    }
                    HttpVersion = GetString(remaining, secondSpace + 1, index);
                    baton.Skip(index + 2);
                    return(true);
                }

                if (ch0 == ' ' && firstSpace == -1)
                {
                    firstSpace = index;
                }
                else if (ch0 == ' ' && firstSpace != -1 && secondSpace == -1)
                {
                    secondSpace = index;
                }
                else if (ch0 == '?' && firstSpace != -1 && questionMark == -1 && secondSpace == -1)
                {
                    questionMark = index;
                }
                ch0 = ch1;
            }
            return(false);
        }
예제 #8
0
        public Connection(ListenerContext context, UvStreamHandle socket)
            : base(context)
        {
            _socket = socket;
            ConnectionControl = this;

            _connectionId = Interlocked.Increment(ref _lastConnectionId);

            SocketInput = new SocketInput(Memory2);
            SocketOutput = new SocketOutput(Thread, _socket, _connectionId, Log);
            _frame = new Frame(this);
        }
예제 #9
0
 private void Execute()
 {
     MessageBody = MessageBody.For(
         HttpVersion,
         RequestHeaders,
         this);
     _keepAlive   = MessageBody.RequestKeepAlive;
     RequestBody  = new FrameRequestStream(MessageBody);
     ResponseBody = new FrameResponseStream(this);
     DuplexStream = new FrameDuplexStream(RequestBody, ResponseBody);
     SocketInput.Free();
     Task.Run(ExecuteAsync);
 }
        public FilteredStreamAdapter(
            Stream filteredStream,
            MemoryPool2 memory,
            IKestrelTrace logger)
        {
            SocketInput = new SocketInput(memory);
            SocketOutput = new StreamSocketOutput(filteredStream);

            _log = logger;
            _filteredStream = filteredStream;
            _socketInputStream = new SocketInputStream(SocketInput);

            _filteredStream.CopyToAsync(_socketInputStream).ContinueWith((task, state) =>
            {
                ((FilteredStreamAdapter)state).OnStreamClose(task);
            }, this);
        }
예제 #11
0
        private void OnRead(UvStreamHandle handle, int readCount, int errorCode, Exception error)
        {
            var normalRead = readCount != 0 && errorCode == 0;
            var normalDone = readCount == 0 && (errorCode == 0 || errorCode == Constants.ECONNRESET || errorCode == Constants.EOF);
            var errorDone  = !(normalDone || normalRead);

            if (normalRead)
            {
                Log.ConnectionRead(_connectionId, readCount);
            }
            else if (normalDone || errorDone)
            {
                _socket.ReadStop();
                Log.ConnectionReadFin(_connectionId);
            }

            SocketInput.IncomingComplete(readCount, errorDone ? error : null);
        }
예제 #12
0
        public void EmptyHeaderValuesCanBeParsed(string rawHeaders, int numHeaders)
        {
            var socketInput = new SocketInput(new MemoryPool2());
            var headerCollection = new FrameRequestHeaders();

            var headerArray = Encoding.ASCII.GetBytes(rawHeaders);
            var inputBuffer = socketInput.IncomingStart(headerArray.Length);
            Buffer.BlockCopy(headerArray, 0, inputBuffer.Data.Array, inputBuffer.Data.Offset, headerArray.Length);
            socketInput.IncomingComplete(headerArray.Length, null);

            var success = Frame.TakeMessageHeaders(socketInput, headerCollection);

            Assert.True(success);
            Assert.Equal(numHeaders, headerCollection.Count());

            // Assert TakeMessageHeaders consumed all the input
            var scan = socketInput.ConsumingStart();
            Assert.True(scan.IsEnd);
        }
        public static async Task <int> ReadAsync(this SocketInput input, ArraySegment <byte> buffer)
        {
            while (true)
            {
                await input;

                var begin = input.ConsumingStart();
                int actual;
                var end = begin.CopyTo(buffer.Array, buffer.Offset, buffer.Count, out actual);
                input.ConsumingComplete(end, end);

                if (actual != 0)
                {
                    return(actual);
                }
                if (input.RemoteIntakeFin)
                {
                    return(0);
                }
            }
        }
예제 #14
0
        /// <summary>
        /// Immediate kill the connection and poison the request and response streams.
        /// </summary>
        public void Abort()
        {
            _requestProcessingStopping = true;
            _requestAborted            = true;

            _requestBody?.Abort();
            _responseBody?.Abort();

            try
            {
                ConnectionControl.End(ProduceEndType.SocketDisconnect);
                SocketInput.AbortAwaiting();
                RequestAbortedSource.Cancel();
            }
            catch (Exception ex)
            {
                Log.LogError("Abort", ex);
            }
            finally
            {
                _abortedCts = null;
            }
        }
        public FilteredStreamAdapter(
            Stream filteredStream,
            MemoryPool2 memory,
            IKestrelTrace logger,
            IThreadPool threadPool)
        {
            SocketInput = new SocketInput(memory, threadPool);
            SocketOutput = new StreamSocketOutput(filteredStream, memory);

            _log = logger;
            _filteredStream = filteredStream;
            _socketInputStream = new SocketInputStream(SocketInput);

            var block = memory.Lease();
            // Use pooled block for copy
            _filteredStream.CopyToAsync(_socketInputStream, block).ContinueWith((task, state) =>
            {
                var returnedBlock = task.Result;
                returnedBlock.Pool.Return(returnedBlock);

                ((FilteredStreamAdapter)state).OnStreamClose(task);
            }, this);
        }
        public async Task ConcurrentReadsFailGracefully()
        {
            // Arrange
            var trace = new KestrelTrace(new TestKestrelTrace());
            var ltp = new LoggingThreadPool(trace);
            using (var memory2 = new MemoryPool2())
            {
                var socketInput = new SocketInput(memory2, ltp);

                var task0Threw = false;
                var task1Threw = false;
                var task2Threw = false;


                var task0 = AwaitAsTaskAsync(socketInput);

                Assert.False(task0.IsFaulted);

                var task = task0.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task0Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                Assert.False(task0.IsFaulted);

                // Awaiting/continuing two tasks faults both

                var task1 = AwaitAsTaskAsync(socketInput);

                await task1.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task1Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                await task;

                Assert.True(task0.IsFaulted);
                Assert.True(task1.IsFaulted);

                Assert.True(task0Threw);
                Assert.True(task1Threw);

                // socket stays faulted

                var task2 = AwaitAsTaskAsync(socketInput);

                await task2.ContinueWith(
                    (t) =>
                    {
                        TestConcurrentFaultedTask(t);
                        task2Threw = true;
                    },
                    TaskContinuationOptions.OnlyOnFaulted);

                Assert.True(task2.IsFaulted);
                Assert.True(task2Threw);
            }
        }
 private async Task AwaitAsTaskAsync(SocketInput socketInput)
 {
     await socketInput;
 }
예제 #18
0
 public LibuvStream(SocketInput input, ISocketOutput output)
 {
     _input = input;
     _output = output;
 }
예제 #19
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 == '%')
                {
                    needDecode = true;
                    chFound = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks);
                }

                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);
                }
                else
                {
                    // URI wasn't encoded, parse as ASCII
                    requestUrlPath = pathBegin.GetAsciiString(pathEnd);
                }

                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);
            }
        }
예제 #20
0
        public static bool TakeMessageHeaders(SocketInput input, FrameRequestHeaders requestHeaders)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                int chFirst;
                int chSecond;
                while (!scan.IsEnd)
                {
                    var beginName = scan;
                    scan.Seek(ref _vectorColons, ref _vectorCRs);
                    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);
                        }
                        throw new InvalidDataException("Malformed request");
                    }

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

                        beginValue = scan;
                        chSecond   = scan.Take();
                    }
                    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 != '\n')
                        {
                            // "\r" was all by itself, move just after it and try again
                            scan = endValue;
                            scan.Take();
                            continue;
                        }

                        var chThird = scan.Peek();
                        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);
            }
        }
예제 #21
0
        private bool TakeMessageHeaders(SocketInput input)
        {
            var scan = input.ConsumingStart();
            var consumed = scan;
            try
            {
                int chFirst;
                int chSecond;
                while (!scan.IsEnd)
                {
                    var beginName = scan;
                    scan.Seek(':', '\r');
                    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;
                        }
                        throw new InvalidDataException("Malformed request");
                    }

                    while (
                        chSecond == ' ' ||
                        chSecond == '\t' ||
                        chSecond == '\r' ||
                        chSecond == '\n')
                    {
                        beginValue = scan;
                        chSecond = scan.Take();
                    }
                    scan = beginValue;

                    var wrapping = false;
                    while (!scan.IsEnd)
                    {
                        if (scan.Seek('\r') == -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 != '\n')
                        {
                            // "\r" was all by itself, move just after it and try again 
                            scan = endValue;
                            scan.Take();
                            continue;
                        }

                        var chThird = scan.Peek();
                        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);
#if DEBUG
                        var nameString = beginName.GetString(endName);
#endif
                        var value = beginValue.GetString(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);
            }
        }
예제 #22
0
            private static bool TakeChunkedLine(SocketInput baton, ref int chunkSizeOut)
            {
                var scan = baton.ConsumingStart();
                var consumed = scan;
                try
                {
                    var ch0 = scan.Take();
                    var chunkSize = 0;
                    var mode = 0;
                    while (ch0 != -1)
                    {
                        var ch1 = scan.Take();
                        if (ch1 == -1)
                        {
                            return false;
                        }

                        if (mode == 0)
                        {
                            if (ch0 >= '0' && ch0 <= '9')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - '0');
                            }
                            else if (ch0 >= 'A' && ch0 <= 'F')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                            }
                            else if (ch0 >= 'a' && ch0 <= 'f')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                            }
                            else
                            {
                                throw new NotImplementedException("INVALID REQUEST FORMAT");
                            }
                            mode = 1;
                        }
                        else if (mode == 1)
                        {
                            if (ch0 >= '0' && ch0 <= '9')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - '0');
                            }
                            else if (ch0 >= 'A' && ch0 <= 'F')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                            }
                            else if (ch0 >= 'a' && ch0 <= 'f')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                            }
                            else if (ch0 == ';')
                            {
                                mode = 2;
                            }
                            else if (ch0 == '\r' && ch1 == '\n')
                            {
                                consumed = scan;
                                chunkSizeOut = chunkSize;
                                return true;
                            }
                            else
                            {
                                throw new NotImplementedException("INVALID REQUEST FORMAT");
                            }
                        }
                        else if (mode == 2)
                        {
                            if (ch0 == '\r' && ch1 == '\n')
                            {
                                consumed = scan;
                                chunkSizeOut = chunkSize;
                                return true;
                            }
                            else
                            {
                                // chunk-extensions not currently parsed
                            }
                        }

                        ch0 = ch1;
                    }
                    return false;
                }
                finally
                {
                    baton.ConsumingComplete(consumed, scan);
                }
            }
예제 #23
0
        private bool TakeStartLine(SocketInput input)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                var begin = scan;
                if (scan.Seek(' ') == -1)
                {
                    return(false);
                }
                var method = begin.GetString(scan);

                scan.Take();
                begin = scan;
                var chFound = scan.Seek(' ', '?');
                if (chFound == -1)
                {
                    return(false);
                }
                var requestUri = begin.GetString(scan);

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

                scan.Take();
                begin = scan;
                if (scan.Seek('\r') == -1)
                {
                    return(false);
                }
                var httpVersion = begin.GetString(scan);

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

                consumed    = scan;
                Method      = method;
                RequestUri  = requestUri;
                QueryString = queryString;
                HttpVersion = httpVersion;
                Path        = RequestUri;
                return(true);
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
예제 #24
0
 private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize)
 {
     return(handle.Libuv.buf_init(
                SocketInput.Pin(2048),
                2048));
 }
예제 #25
0
        private bool TakeStartLine(SocketInput input)
        {
            var scan     = input.ConsumingStart();
            var consumed = scan;

            try
            {
                var begin = scan;
                if (scan.Seek(' ') == -1)
                {
                    return(false);
                }
                var method = begin.GetString(scan);

                scan.Take();
                begin = scan;

                var needDecode = false;
                var chFound    = scan.Seek(' ', '?', '%');
                if (chFound == '%')
                {
                    needDecode = true;
                    chFound    = scan.Seek(' ', '?');
                }

                var pathBegin = begin;
                var pathEnd   = scan;

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

                scan.Take();
                begin = scan;
                if (scan.Seek('\r') == -1)
                {
                    return(false);
                }
                var httpVersion = begin.GetString(scan);

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

                if (needDecode)
                {
                    pathEnd = UrlPathDecoder.Unescape(pathBegin, pathEnd);
                }

                var requestUrlPath = pathBegin.GetString(pathEnd);

                consumed    = scan;
                Method      = method;
                RequestUri  = requestUrlPath;
                QueryString = queryString;
                HttpVersion = httpVersion;
                Path        = RequestUri;
                return(true);
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
예제 #26
0
        public void Start()
        {
            KestrelTrace.Log.ConnectionStart(_connectionId);

            SocketInput = new SocketInput(Memory);
            SocketOutput = new SocketOutput(Thread, _socket);
            _frame = new Frame(this);
            _socket.ReadStart(_allocCallback, _readCallback, this);
        }
예제 #27
0
        private bool TakeStartLine(SocketInput input)
        {
            var scan = input.ConsumingStart();
            var consumed = scan;
            try
            {
                var begin = scan;
                if (scan.Seek(' ') == -1)
                {
                    return false;
                }
                var method = begin.GetString(scan);

                scan.Take();
                begin = scan;

                var needDecode = false;
                var chFound = scan.Seek(' ', '?', '%');
                if (chFound == '%')
                {
                    needDecode = true;
                    chFound = scan.Seek(' ', '?');
                }

                var pathBegin = begin;
                var pathEnd = scan;

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

                scan.Take();
                begin = scan;
                if (scan.Seek('\r') == -1)
                {
                    return false;
                }
                var httpVersion = begin.GetString(scan);

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

                if (needDecode)
                {
                    pathEnd = UrlPathDecoder.Unescape(pathBegin, pathEnd);
                }

                var requestUrlPath = pathBegin.GetString(pathEnd);

                consumed = scan;
                Method = method;
                RequestUri = requestUrlPath;
                QueryString = queryString;
                HttpVersion = httpVersion;
                Path = RequestUri;
                return true;
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
예제 #28
0
            private static bool TakeChunkedLine(SocketInput baton, ref int chunkSizeOut)
            {
                var remaining = baton.Buffer;

                if (remaining.Count < 2)
                {
                    return(false);
                }
                var ch0       = remaining.Array[remaining.Offset];
                var chunkSize = 0;
                var mode      = 0;

                for (var index = 0; index != remaining.Count - 1; ++index)
                {
                    var ch1 = remaining.Array[remaining.Offset + index + 1];

                    if (mode == 0)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                        mode = 1;
                    }
                    else if (mode == 1)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else if (ch0 == ';')
                        {
                            mode = 2;
                        }
                        else if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return(true);
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                    }
                    else if (mode == 2)
                    {
                        if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return(true);
                        }
                        else
                        {
                            // chunk-extensions not currently parsed
                        }
                    }

                    ch0 = ch1;
                }
                return(false);
            }
예제 #29
0
        private bool TakeStartLine(SocketInput input)
        {
            var scan = input.ConsumingStart();
            var consumed = scan;
            try
            {
                var begin = scan;
                if (scan.Seek(' ') == -1)
                {
                    return false;
                }
                var method = begin.GetString(scan);

                scan.Take();
                begin = scan;
                var chFound = scan.Seek(' ', '?');
                if (chFound == -1)
                {
                    return false;
                }
                var requestUri = begin.GetString(scan);

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

                scan.Take();
                begin = scan;
                if (scan.Seek('\r') == -1)
                {
                    return false;
                }
                var httpVersion = begin.GetString(scan);

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

                consumed = scan;
                Method = method;
                RequestUri = requestUri;
                QueryString = queryString;
                HttpVersion = httpVersion;
                Path = RequestUri;
                return true;
            }
            finally
            {
                input.ConsumingComplete(consumed, scan);
            }
        }
 public SocketInputStream(SocketInput socketInput)
 {
     _socketInput = socketInput;
 }
예제 #31
0
            private static bool TakeChunkedLine(SocketInput baton, ref int chunkSizeOut)
            {
                var remaining = baton.Buffer;
                if (remaining.Count < 2)
                {
                    return false;
                }
                var ch0 = remaining.Array[remaining.Offset];
                var chunkSize = 0;
                var mode = 0;
                for (var index = 0; index != remaining.Count - 1; ++index)
                {
                    var ch1 = remaining.Array[remaining.Offset + index + 1];

                    if (mode == 0)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                        mode = 1;
                    }
                    else if (mode == 1)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else if (ch0 == ';')
                        {
                            mode = 2;
                        }
                        else if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return true;
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                    }
                    else if (mode == 2)
                    {
                        if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return true;
                        }
                        else
                        {
                            // chunk-extensions not currently parsed
                        }
                    }

                    ch0 = ch1;
                }
                return false;
            }
예제 #32
0
        private bool TakeStartLine(SocketInput baton)
        {
            var remaining = baton.Buffer;
            if (remaining.Count < 2)
            {
                return false;
            }
            var firstSpace = -1;
            var secondSpace = -1;
            var questionMark = -1;
            var ch0 = remaining.Array[remaining.Offset];
            for (var index = 0; index != remaining.Count - 1; ++index)
            {
                var ch1 = remaining.Array[remaining.Offset + index + 1];
                if (ch0 == '\r' && ch1 == '\n')
                {
                    if (secondSpace == -1)
                    {
                        throw new InvalidOperationException("INVALID REQUEST FORMAT");
                    }
                    Method = GetString(remaining, 0, firstSpace);
                    RequestUri = GetString(remaining, firstSpace + 1, secondSpace);
                    if (questionMark == -1)
                    {
                        Path = RequestUri;
                        QueryString = string.Empty;
                    }
                    else
                    {
                        Path = GetString(remaining, firstSpace + 1, questionMark);
                        QueryString = GetString(remaining, questionMark, secondSpace);
                    }
                    HttpVersion = GetString(remaining, secondSpace + 1, index);
                    baton.Skip(index + 2);
                    return true;
                }

                if (ch0 == ' ' && firstSpace == -1)
                {
                    firstSpace = index;
                }
                else if (ch0 == ' ' && firstSpace != -1 && secondSpace == -1)
                {
                    secondSpace = index;
                }
                else if (ch0 == '?' && firstSpace != -1 && questionMark == -1 && secondSpace == -1)
                {
                    questionMark = index;
                }
                ch0 = ch1;
            }
            return false;
        }
예제 #33
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 == '%')
                {
                    needDecode = true;
                    chFound    = scan.Seek(ref _vectorSpaces, ref _vectorQuestionMarks);
                }

                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);
                }
                else
                {
                    // URI wasn't encoded, parse as ASCII
                    requestUrlPath = pathBegin.GetAsciiString(pathEnd);
                }

                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);
            }
        }
예제 #34
0
        private bool TakeMessageHeader(SocketInput baton, out bool endOfHeaders)
        {
            var remaining = baton.Buffer;
            endOfHeaders = false;
            if (remaining.Count < 2)
            {
                return false;
            }
            var ch0 = remaining.Array[remaining.Offset];
            var ch1 = remaining.Array[remaining.Offset + 1];
            if (ch0 == '\r' && ch1 == '\n')
            {
                endOfHeaders = true;
                baton.Skip(2);
                return true;
            }

            if (remaining.Count < 3)
            {
                return false;
            }
            var wrappedHeaders = false;
            var colonIndex = -1;
            var valueStartIndex = -1;
            var valueEndIndex = -1;
            for (var index = 0; index != remaining.Count - 2; ++index)
            {
                var ch2 = remaining.Array[remaining.Offset + index + 2];
                if (ch0 == '\r' &&
                    ch1 == '\n' &&
                        ch2 != ' ' &&
                            ch2 != '\t')
                {
                    var name = Encoding.ASCII.GetString(remaining.Array, remaining.Offset, colonIndex);
                    var value = "";
                    if (valueEndIndex != -1)
                    {
                        value = Encoding.ASCII.GetString(
                            remaining.Array, remaining.Offset + valueStartIndex, valueEndIndex - valueStartIndex);
                    }
                    if (wrappedHeaders)
                    {
                        value = value.Replace("\r\n", " ");
                    }
                    AddRequestHeader(name, value);
                    baton.Skip(index + 2);
                    return true;
                }
                if (colonIndex == -1 && ch0 == ':')
                {
                    colonIndex = index;
                }
                else if (colonIndex != -1 &&
                    ch0 != ' ' &&
                        ch0 != '\t' &&
                            ch0 != '\r' &&
                                ch0 != '\n')
                {
                    if (valueStartIndex == -1)
                    {
                        valueStartIndex = index;
                    }
                    valueEndIndex = index + 1;
                }
                else if (!wrappedHeaders &&
                    ch0 == '\r' &&
                        ch1 == '\n' &&
                            (ch2 == ' ' ||
                                ch2 == '\t'))
                {
                    wrappedHeaders = true;
                }

                ch0 = ch1;
                ch1 = ch2;
            }
            return false;
        }
예제 #35
0
            private static bool TakeChunkedLine(SocketInput baton, ref int chunkSizeOut)
            {
                var scan     = baton.ConsumingStart();
                var consumed = scan;

                try
                {
                    var ch0       = scan.Take();
                    var chunkSize = 0;
                    var mode      = 0;
                    while (ch0 != -1)
                    {
                        var ch1 = scan.Take();
                        if (ch1 == -1)
                        {
                            return(false);
                        }

                        if (mode == 0)
                        {
                            if (ch0 >= '0' && ch0 <= '9')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - '0');
                            }
                            else if (ch0 >= 'A' && ch0 <= 'F')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                            }
                            else if (ch0 >= 'a' && ch0 <= 'f')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                            }
                            else
                            {
                                throw new NotImplementedException("INVALID REQUEST FORMAT");
                            }
                            mode = 1;
                        }
                        else if (mode == 1)
                        {
                            if (ch0 >= '0' && ch0 <= '9')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - '0');
                            }
                            else if (ch0 >= 'A' && ch0 <= 'F')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                            }
                            else if (ch0 >= 'a' && ch0 <= 'f')
                            {
                                chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                            }
                            else if (ch0 == ';')
                            {
                                mode = 2;
                            }
                            else if (ch0 == '\r' && ch1 == '\n')
                            {
                                consumed     = scan;
                                chunkSizeOut = chunkSize;
                                return(true);
                            }
                            else
                            {
                                throw new NotImplementedException("INVALID REQUEST FORMAT");
                            }
                        }
                        else if (mode == 2)
                        {
                            if (ch0 == '\r' && ch1 == '\n')
                            {
                                consumed     = scan;
                                chunkSizeOut = chunkSize;
                                return(true);
                            }
                            else
                            {
                                // chunk-extensions not currently parsed
                            }
                        }

                        ch0 = ch1;
                    }
                    return(false);
                }
                finally
                {
                    baton.ConsumingComplete(consumed, scan);
                }
            }
예제 #36
0
        private bool TakeMessageHeader(SocketInput baton, out bool endOfHeaders)
        {
            var remaining = baton.Buffer;

            endOfHeaders = false;
            if (remaining.Count < 2)
            {
                return(false);
            }
            var ch0 = remaining.Array[remaining.Offset];
            var ch1 = remaining.Array[remaining.Offset + 1];

            if (ch0 == '\r' && ch1 == '\n')
            {
                endOfHeaders = true;
                baton.Skip(2);
                return(true);
            }

            if (remaining.Count < 3)
            {
                return(false);
            }
            var wrappedHeaders  = false;
            var colonIndex      = -1;
            var valueStartIndex = -1;
            var valueEndIndex   = -1;

            for (var index = 0; index != remaining.Count - 2; ++index)
            {
                var ch2 = remaining.Array[remaining.Offset + index + 2];
                if (ch0 == '\r' &&
                    ch1 == '\n' &&
                    ch2 != ' ' &&
                    ch2 != '\t')
                {
                    var name  = Encoding.ASCII.GetString(remaining.Array, remaining.Offset, colonIndex);
                    var value = "";
                    if (valueEndIndex != -1)
                    {
                        value = Encoding.ASCII.GetString(
                            remaining.Array, remaining.Offset + valueStartIndex, valueEndIndex - valueStartIndex);
                    }
                    if (wrappedHeaders)
                    {
                        value = value.Replace("\r\n", " ");
                    }
                    AddRequestHeader(name, value);
                    baton.Skip(index + 2);
                    return(true);
                }
                if (colonIndex == -1 && ch0 == ':')
                {
                    colonIndex = index;
                }
                else if (colonIndex != -1 &&
                         ch0 != ' ' &&
                         ch0 != '\t' &&
                         ch0 != '\r' &&
                         ch0 != '\n')
                {
                    if (valueStartIndex == -1)
                    {
                        valueStartIndex = index;
                    }
                    valueEndIndex = index + 1;
                }
                else if (!wrappedHeaders &&
                         ch0 == '\r' &&
                         ch1 == '\n' &&
                         (ch2 == ' ' ||
                          ch2 == '\t'))
                {
                    wrappedHeaders = true;
                }

                ch0 = ch1;
                ch1 = ch2;
            }
            return(false);
        }