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); } } }
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()); } }
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)); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
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); } } }
/// <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; }
public LibuvStream(SocketInput input, ISocketOutput output) { _input = input; _output = output; }
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); } }
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); } }
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); } }
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); } }
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); } }
private Libuv.uv_buf_t OnAlloc(UvStreamHandle handle, int suggestedSize) { return(handle.Libuv.buf_init( SocketInput.Pin(2048), 2048)); }
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); } }
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); } }
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); }
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; }
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; }
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; }
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); } }
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; }
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); } }
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); }