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); } } }
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); } } }
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); } }
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); } }
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 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 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 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); } }
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 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); } }