private static async Task <string> ReadCRLFLineAsync(Stream stream, Encoding encoding, CancellationToken ctsToken = default) { var bab = new ByteArrayBuilder(); while (true) { int ch = await stream.ReadByteAsync(ctsToken); if (ch == -1) { break; } if (ch == '\r') { var ch2 = await stream.ReadByteAsync(ctsToken); if (ch2 == '\n') { return(bab.ToString(encoding)); } bab.Append(new byte[] { (byte)ch, (byte)ch2 }); continue; } bab.Append((byte)ch); } if (bab.Length > 0) { return(bab.ToString(encoding)); } return(null); }
private static async Task <string> ReadCRLFLineAsync(Stream stream, Encoding encoding, CancellationToken ctsToken = default) { var bab = new ByteArrayBuilder(); while (true) { int ch = await stream.ReadByteAsync(ctsToken).ConfigureAwait(false); if (ch == -1) { break; } if (ch == '\r') { var ch2 = await stream.ReadByteAsync(ctsToken).ConfigureAwait(false); if (ch2 == '\n') { return(bab.ToString(encoding)); } bab.Append(new byte[] { (byte)ch, (byte)ch2 }); continue; } bab.Append((byte)ch); } return(bab.Length > 0 ? bab.ToString(encoding) : throw new FormatException("There's no CRLF.")); }
public static async Task <string> ReadStartLineAsync(Stream stream, CancellationToken ctsToken = default) { // https://tools.ietf.org/html/rfc7230#section-3 // A recipient MUST parse an HTTP message as a sequence of octets in an // encoding that is a superset of US-ASCII[USASCII]. // Read until the first CRLF // the CRLF is part of the startLine // https://tools.ietf.org/html/rfc7230#section-3.5 // Although the line terminator for the start-line and header fields is // the sequence CRLF, a recipient MAY recognize a single LF as a line // terminator and ignore any preceding CR. var bab = new ByteArrayBuilder(); int read = 0; while (read >= 0) { read = await stream.ReadByteAsync(ctsToken).ConfigureAwait(false); bab.Append((byte)read); if (LF == (byte)read) { break; } } var startLine = bab.ToString(Encoding.ASCII); if (string.IsNullOrEmpty(startLine)) { throw new FormatException($"{nameof(startLine)} cannot be null or empty."); } return(startLine); }
async Task <string> ReadLineAsync(bool doAsync, CancellationToken cancellationToken) { if (stream == null) { throw new InvalidOperationException(); } using (var builder = new ByteArrayBuilder(64)) { bool complete; do { if (doAsync) { complete = await stream.ReadLineAsync(builder, cancellationToken).ConfigureAwait(false); } else { complete = stream.ReadLine(builder, cancellationToken); } } while (!complete); // FIXME: All callers expect CRLF to be trimmed, but many also want all trailing whitespace trimmed. builder.TrimNewLine(); return(builder.ToString()); } }
public async Task TestReadLineAsync() { var line1 = "This is a really long line..." + new string ('.', 4096) + "\r\n"; var line2 = "And this is another line...\r\n"; using (var stream = new ImapStream(new DummyNetworkStream(), new NullProtocolLogger())) { var data = Encoding.ASCII.GetBytes(line1 + line2); stream.Stream.Write(data, 0, data.Length); stream.Stream.Position = 0; using (var builder = new ByteArrayBuilder(64)) { while (!await stream.ReadLineAsync(builder, CancellationToken.None)) { ; } var text = builder.ToString(); Assert.AreEqual(line1, text, "Line1"); } using (var builder = new ByteArrayBuilder(64)) { while (!await stream.ReadLineAsync(builder, CancellationToken.None)) { ; } var text = builder.ToString(); Assert.AreEqual(line2, text, "Line2"); } } }
public void ToStringTest() { using (ByteArrayBuilder builder = new ByteArrayBuilder()) { builder.Append((byte)0x68); builder.Append((byte)0x01); builder.Append((byte)0x01); builder.Append((byte)0x02); builder.Append(new byte[2] { 0x03, 0x04 }); string _data = builder.ToString(); string _expected = "68 01 01 02 03 04"; Assert.AreEqual(_expected, _data); } }
public static async Task <string> ReadStartLineAsync(Stream stream, CancellationToken ctsToken = default) { // https://tools.ietf.org/html/rfc7230#section-3 // A recipient MUST parse an HTTP message as a sequence of octets in an // encoding that is a superset of US-ASCII[USASCII]. // Read until the first CRLF // the CRLF is part of the startLine // https://tools.ietf.org/html/rfc7230#section-3.5 // Although the line terminator for the start-line and header fields is // the sequence CRLF, a recipient MAY recognize a single LF as a line // terminator and ignore any preceding CR. var bab = new ByteArrayBuilder(); int read = 0; while (read >= 0) { read = await stream.ReadByteAsync(ctsToken).ConfigureAwait(false); // End of stream has been reached. if (read == -1) { Logger.LogTrace($"End of stream has been reached during reading HTTP start-line. Read bytes: '{ByteHelpers.ToHex(bab.ToArray())}'."); throw new TorConnectionReadException("HTTP start-line is incomplete. Tor circuit probably died."); } bab.Append((byte)read); if (LF == (byte)read) { break; } } var startLine = bab.ToString(Encoding.ASCII); if (string.IsNullOrEmpty(startLine)) { throw new FormatException($"{nameof(startLine)} cannot be null or empty."); } return(startLine); }
public static ImapToken Create(ImapTokenType type, ByteArrayBuilder builder) { string value; if (type == ImapTokenType.Flag) { foreach (var token in CommonMessageFlagTokens) { value = (string)token.Value; if (builder.Equals(value, true)) { return(token); } } } else if (builder.Equals("NIL", true)) { foreach (var token in NilTokens) { value = (string)token.Value; if (builder.Equals(value)) { return(token); } } var nil = new ImapToken(ImapTokenType.Nil, builder.ToString()); NilTokens.Add(nil); return(nil); } else { if (builder.Equals("FETCH", false)) { return(Fetch); } if (builder.Equals("BODY", false)) { return(Body); } if (builder.Equals("BODYSTRUCTURE", false)) { return(BodyStructure); } if (builder.Equals("ENVELOPE", false)) { return(Envelope); } if (builder.Equals("FLAGS", false)) { return(Flags); } if (builder.Equals("INTERNALDATE", false)) { return(InternalDate); } if (builder.Equals("MODSEQ", false)) { return(ModSeq); } if (builder.Equals("RFC822.SIZE", false)) { return(Rfc822Size); } if (builder.Equals("UID", false)) { return(Uid); } if (builder.Equals("X-GM-LABELS", false)) { return(XGMLabels); } if (builder.Equals("X-GM-MSGID", false)) { return(XGMMsgId); } if (builder.Equals("X-GM-THRID", false)) { return(XGMThrId); } } value = builder.ToString(); return(new ImapToken(type, value)); }
async Task <SmtpResponse> ReadResponseAsync(bool doAsync, CancellationToken cancellationToken) { CheckDisposed(); using (var builder = new ByteArrayBuilder(256)) { bool needInput = inputIndex == inputEnd; bool complete = false; bool newLine = true; bool more = true; int code = 0; do { if (needInput) { await ReadAheadAsync(doAsync, cancellationToken).ConfigureAwait(false); needInput = false; } complete = false; do { int startIndex = inputIndex; if (newLine && inputIndex < inputEnd) { if (!ByteArrayBuilder.TryParse(input, ref inputIndex, inputEnd, out int value)) { throw new SmtpProtocolException("Unable to parse status code returned by the server."); } if (inputIndex == inputEnd) { inputIndex = startIndex; needInput = true; break; } if (code == 0) { code = value; } else if (value != code) { throw new SmtpProtocolException("The status codes returned by the server did not match."); } newLine = false; if (input[inputIndex] != (byte)'\r' && input[inputIndex] != (byte)'\n') { more = input[inputIndex++] == (byte)'-'; } else { more = false; } startIndex = inputIndex; } while (inputIndex < inputEnd && input[inputIndex] != (byte)'\r' && input[inputIndex] != (byte)'\n') { inputIndex++; } builder.Append(input, startIndex, inputIndex - startIndex); if (inputIndex < inputEnd && input[inputIndex] == (byte)'\r') { inputIndex++; } if (inputIndex < inputEnd && input[inputIndex] == (byte)'\n') { if (more) { builder.Append(input[inputIndex]); } complete = true; newLine = true; inputIndex++; } } while (more && inputIndex < inputEnd); if (inputIndex == inputEnd) { needInput = true; } } while (more || !complete); var message = builder.ToString(); return(new SmtpResponse((SmtpStatusCode)code, message)); } }